Java数字证书与HHTPS安全通信

来源:互联网 发布:rewrite 知乎 编辑:程序博客网 时间:2024/05/16 17:17

1.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工具,可以用来创建秘钥库,导出自己的证书

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

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

 

2. 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协议介绍到这里为止 

0 0
原创粉丝点击