Java数字证书与https安全通信

Java 04/17 阅读 332 views次 人气 0
摘要:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

一.Java 数字证书

JDK 自带 keytool工具,在 jdk\bin 目录下,可以用来管理秘钥库、证书数据库和私有秘钥。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

秘钥库中每一项都拥有一个别名,在cmd命令行输入 keytool -help 命令可以查看该工具的使用方法

1.1 生成自己的证书并导出

(1)创建秘钥库

keytool -genkeypair  -keystore  myCert.certs  -alias  myCert

执行这个命令之后,就会在当前目录就会生成秘钥库文件 myCert.certs ,如下所示

 

(2)导出证书

将秘钥库的公共秘钥导出成证书,就可以给其他人或者组织使用

只不过这种个人证书,是没有经过第三方担保的,可信度不高

keytool  -exportcert  -keystore  myCert.certs  -alias  myCert  -file  my.cer

执行完命令,在当前目录就会生成证书,证书是包含了公钥的,如下

(3)查看证书

keytool  -printcert  -file  my.cer     结果如下所示

1.2 客户端导入证书

假设你把证书发给你的客户 Lily,现在她需要把证书导入到证书库才可以使用,Lily只需要这么操作

keytool -importcert -keystore  lily.certs  -alias lily  -file  my.cer

1.3 使用证书

(1)使用证书签名

接下来我们使用 jarsigner 这个工具,将一个文档签名,就使用你自己创建的证书来签名

jarsigner  -keystore  myCert.certs  test.jar  myCert

(2)使用证书校验

然后你可以把签名过的文档,也就是 test.jar 发送给客户端,比如就是Lily

她使用你给她的证书来校验:这个文档是否确实是你签名过的

jarsigner  -verify  -keystore  lily.certs  test.jar

如果打印出来 jar 已验证  说明认证成功

至此我们了解JDK自带的keytool和jarsigner工具,可以用来创建秘钥库,导出自己的证书

也可以发送证书给客户端使用,客户端只要导入证书,并使用证书来认证签名即可

总的来说:数字签名就是具备 不可否认性 完整性 的功效

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

二. HTTPS 协议

https协议就简单看做http协议的简单版本,他是在TCP/IP层与HTTP应用层之间

加入SSL协议,保证数据传输的安全性,因为采用加密传输,所以即使被盗窃

没有秘钥解密也是没问题的,至于https协议的握手过程,可以看书或者网上都能找到

这里要介绍的是如何把 数字证书 与 HTTPS 协议结合起来使用

2.1 Tomcat 配置SSL协议

我们知道http请求使用80端口,https则使用443端口

证书在第一步我们已经生成了,接下来我们就把数字证书配置到Tomcat服务器

打开Tomcat 的server.xml 配置文件,配置SSL服务

<Connector SSLEnabled="true" clientAuth="false"
			keystoreFile="C:/Users/Administrator/myCert.certs" keystorePass="123456"
			maxThreads="150" port="8443" protocol="HTTP/1.1" scheme="https"
			secure="true" sslProtocol="TLS" />

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

keystoreFile:秘钥库文件的地址,这是你自己在第一步就已经生成的

keystorePass:秘钥库主密码,就是你自己创建秘钥库时输入的密码

接下来,你只要创建一个Web应用,然后就可以使用https协议方式来访问了

到此为止:数字证书已经和https协议结合起来使用了

只不过浏览器访问时:仍然会提示这个证书是需要客户端自己担责的,因为这个证书没有经过第三方比如CA认证

2.2 通过SSL安全套接字来访问https服务

package com.yli.security;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class SSLTest {
    
    public static void main(String[] args) throws IOException {
        
       // 创建URL对象
        URL myURL = new URL("https://localhost:8443/SSlWeb/index.jsp");

        // 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
        HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();

        // 取得该连接的输入流,以读取响应内容
        InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream());

        
        BufferedReader r =  new BufferedReader(insr);
        String line;
        while((line = r.readLine())!=null) {
            System.out.println(line);
        }
        
    }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

一般情况下,直接运行会报错,最常见的就是:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

这是因为Java的安全机制造成的:客户端的TrustStore文件中保存着被客户端所信任的服务器的证书信息。

客户端在进行SSL连接时,JSSE将根据这个文件中的证书决定是否信任服务器端的证书。

在SunJSSE中,有一个信任管理器类负责决定是否信任远端的证书,这个类有如下的处理规则:

1)若系统属性javax.net.sll.trustStore指定了TrustStore文件,那么信任管理器就去jre安装路径下的lib/security/目录中寻找并使用这个文件来检查证书。

2)若该系统属性没有指定TrustStore文件,它就会去jre安装路径下寻找默认的TrustStore文件,这个文件的相对路径为:lib/security/jssecacerts

3)若jssecacerts不存在,但是cacerts存在(它随J2SDK一起发行,含有数量有限的可信任的基本证书),那么这个默认的TrustStore文件就是lib/security/cacerts

在这种情况下,最简单的解决办法就是把证书导入到 jdk\jre\lib\security\caerts 证书库中

keytool -import  -alias myCert_for_serverkey  -file my.cer  -keystore  %JAVA_HOME%\jre\lib\security\cacerts

特别留意:这是要把证书导入到jdk的证书库中,输入密码是 changeit  这是jdk证书库的默认密码!!!

接下来,你再运行之前的程序,可能还会报错,不过应该是这种错误了:

java.security.cert.CertificateException: No name matching localhost found

如果不是这种错误:请你检查,你Eclipse工作空间的jdk,是不是使用刚才导入证书库的jdk呢!!!!

如果是这种错误,需要我们实现 HostnameVerifier 接口,才能正常使用,完整代码如下

package com.yli.security;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class SSLTest {
    
    public static void main(String[] args) throws IOException {
        
       // 创建URL对象
        URL myURL = new URL("https://localhost:8443/SSlWeb/index.jsp");

        // 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
        HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();

        // 设置hostname 校验
        httpsConn.setHostnameVerifier(new MyHostnameVerifier());
        
        // 取得该连接的输入流,以读取响应内容
        InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream());

        
        BufferedReader r =  new BufferedReader(insr);
        String line;
        while((line = r.readLine())!=null) {
            System.out.println(line);
        }
        
    }
}

class MyHostnameVerifier implements HostnameVerifier {
    @Override
    public boolean verify(String hostname, SSLSession sslSession) {
        if (hostname.equals("localhost")) {
            return true;
        }
        return false;
    }
    
    
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这个时候,如果你是按照步骤一步一步来实现的,应该就成功运行了,能看到输出结果

好了,简单的数字证书与签名,以及怎么使用HTTPS协议介绍到这里为止 

小奋斗文章

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

评论

该文章不支持评论!

分享到: