基于SSL的https如何进行双方验证?咱们能够参考 一样基于SSL的SSH的验证过程 html
参考百度百科 SSH java
依靠密匙,也就是你必须为本身建立一对密匙-公钥,并把公匙放在须要访问的服务器上。如你要链接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求以后,先在该服务器上你的主目录下寻找你的公用密匙,而后把它和你发送过来的公用密匙进行比较。若是两个密匙一致,服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。客户端软件收到“质询”以后就能够用你的私人密匙解密再把它发送给服务器。 web
非对称加密算法中 公钥用来加密 私钥用来解密 算法
首先要 确立几个概念 apache
keyStore 、证书、密钥 浏览器
keyStore(java键库) 是 由java的keytool命令生成的,键库是一个用来集中存放 私钥公钥的地方 tomcat
在keystore里,包含两种数据: 安全
(1)密钥实体(Key entity):密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
(2)可信任的证书实体(trusted certificate entries):只包含公钥,别人的公钥 服务器
Java KeyStore的类型常见的包括了 JKS, JCEKS, PKCS12, BKS,UBER 测试
JKS是默认的类型
咱们开始动手利用keytool生成相关私钥和证书了
一、生成服务器证书库(CN=127.0.0.1 这个 域 须要是server被访问的地址)
keytool -validity 365 -genkey -v -alias server -keyalg RSA -keystore D:\ssl\server.keystore -dname "CN=127.0.0.1" -storepass 123456 -keypass 123456
二、生成客户端证书库
keytool -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore D:\ssl\client.p12 -dname "CN=client" -storepass 123456 -keypass 123456
三、从客户端证书库中导出客户端证书
keytool -export -v -alias client -keystore D:\ssl\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\ssl\client.cer
4、从服务器证书库中导出服务器证书
keytool -export -v -alias server -keystore D:\ssl\server.keystore -storepass 123456 -rfc -file D:\ssl\server.cer
5、生成客户端信任证书库(由服务端证书生成的证书库)
keytool -import -v -alias server -file D:\ssl\server.cer -keystore D:\ssl\client.truststore -storepass 123456
6、将客户端证书导入到服务器证书库(使得服务器信任客户端证书)
keytool -import -v -alias client -file D:\ssl\client.cer -keystore D:\ssl\server.keystore -storepass 123456
7、查看证书库中的所有证书
keytool -list -keystore D:\ssl\server.keystore -storepass 123456
如今咱们来看看咱们生成了哪些文件:
client.p12 (客户端的keyStore,它的storetype 是 PKCS12) client.truststore(客户端keyStore 存放了server端的公钥 server.cer) client.cer (客户端公钥)
server.keystore(服务端keyStore 存放了client.cer 和本身的私钥) server.cer (server 端公钥)
涉及keytool有几个关键命令参数解释一下:-genkeypair 生成密钥对 你能够理解为 虽然公钥私钥都生成了 可是 list查看 keyStore显示的是私钥 你要使用公钥须要命令 -export 产生 .cer文件,而导出的公钥须要 -import 命令导入到别人的keyStore里
简单的记忆就是keyStore里存放的是本身的私钥 和 导入的别人的公钥 (受信任的别人),从keyStore中也能够生成本身的公钥
-storepass 指定了 keyStore的密码,-keypass 指定了生成的那一条私钥的密码
接下来修改 服务器端,实现https与servlet代码无关,与java web容器有关,以tomcat为例
修改 {tomcat}/conf/server.xml,找到Connector port="8443"的标签,取消注释,并修改
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS" keystoreFile="D:\ssl\server.keystore" keystorePass="123456" truststoreFile="D:\ssl\server.keystore" truststorePass="123456"/>
几个修改点注意 protocol修改成org.apache.coyote.http11.Http11NioProtocol 避免了配置APR相关
clientAuth="true" 使得 server端 对 client端来的请求进行验证
sslProtocol="TLS" 指明了采用TLS做为SSL实现的具体协议(参考TLS和SSL的关系)
keystoreFile 和 truststoreFile 指明keyStore
而后编写servlet代码例子测试下,其中还额外指明了如何获取证书信息(clientAuth="true" server已经对client进行验证了,只有被server信任的client才能握手成功)
package com.icesoft.servlet; import java.io.IOException; import java.io.PrintWriter; import java.security.cert.X509Certificate; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * <p> * SSL Servlet * </p> * * @author IceWee * @date 2012-6-4 * @version 1.0 */ public class SSLServlet extends HttpServlet { private static final long serialVersionUID = 1601507150278487538L; private static final String ATTR_CER = "javax.servlet.request.X509Certificate"; private static final String CONTENT_TYPE = "text/plain;charset=UTF-8"; private static final String DEFAULT_ENCODING = "UTF-8"; private static final String SCHEME_HTTPS = "https"; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); response.setCharacterEncoding(DEFAULT_ENCODING); PrintWriter out = response.getWriter(); X509Certificate[] certs = (X509Certificate[]) request.getAttribute(ATTR_CER); if (certs != null) { int count = certs.length; out.println("共检测到[" + count + "]个客户端证书"); for (int i = 0; i < count; i++) { out.println("客户端证书 [" + (++i) + "]: "); out.println("校验结果:" + verifyCertificate(certs[--i])); out.println("证书详细:\r" + certs[i].toString()); } } else { if (SCHEME_HTTPS.equalsIgnoreCase(request.getScheme())) { out.println("这是一个HTTPS请求,可是没有可用的客户端证书"); } else { out.println("这不是一个HTTPS请求,所以没法得到客户端证书列表 "); } } out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * <p> * 校验证书是否过时 * </p> * * @param certificate * @return */ private boolean verifyCertificate(X509Certificate certificate) { boolean valid = true; try { certificate.checkValidity(); } catch (Exception e) { e.printStackTrace(); valid = false; } return valid; } }
若是咱们给浏览器安装了client.p12,就能经过浏览器访问server了 https://127.0.0.1:8443/ssl
咱们若是须要本身编写代码 以https的方式访问server应该如何实现呢?这里以apache的http client做为示例
KeyStore myKey=KeyStore.getInstance("pkcs12"); myKey.load(new FileInputStream("d:/ssl/client.p12"),"123456".toCharArray()); KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); myTrustStore.load(new FileInputStream("d:/ssl/client.truststore"),"123456".toCharArray()); SSLContext sslContext = SSLContexts.custom() .useTLS() .loadKeyMaterial(myKey,"123456".toCharArray()) .loadTrustMaterial(myTrustStore) .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslsf).build(); HttpGet get = new HttpGet(); get.setURI(new URI("https://127.0.0.1:8443/ssl")); CloseableHttpResponse response = client.execute(get); ByteArrayOutputStream out = new ByteArrayOutputStream(); response.getEntity().writeTo(out); System.out.println(new String(out.toByteArray(),"utf8")); out.close(); response.close();
useTLS 指明了所使用的协议类型 、
loadKeyMaterial(myKey,"123456".toCharArray()) 加载client的私钥,注意这里的123456不是keyStore的密码 而是私钥的密码 由-keypass 123456指定的 ,也就是keyStore有一个密码 而这个store内每一条密钥还能够指定单独密码 、
loadTrustMaterial 加载受信任的证书 包含server的公钥
整个过程打通,经过https 来实现接口 1,能够利用http协议自己的成熟简单 开发成本低。2 https的数据传输过程是被保护的,数据不会被截取。3 能够经过控制 server端的 受信任证书库 keyStore 添加或删除 公钥来控制访问方的访问权限
参考
(全程参考)http://www.blogjava.net/icewee/archive/2012/06/04/379947.html
(java keytool命令总结)http://gwh-08.iteye.com/blog/1779667
(TLS和SSL的关系)http://www.360doc.com/content/09/1231/02/495229_12346441.shtml
(不一样格式的keyStore)http://blog.chinaunix.net/uid-15473693-id-87588.html