标签:
SSL(Secure Sockets Layer 安全套接层)就是一种协议(规范),用于保障客户端和服务器端通信的安全,以免通信时传输的信息被窃取或者修改。
客户端和服务器端在进行握手(客户端和服务器建立连接和交换参数的过程称之为握手)时会产生一个“对话密钥”(session key),用来加密接下来的数据传输,解密时也是用的这个“对话密钥”,而这个“对话密钥”只有客户端和服务器端知道。也就是说只要这个“对话密钥”不被破解,就能保证安全。
2. 客户端证书和服务器端证书
客户端证书和服务器端证书用于证明自己的身份,就好比每个人都有一张身份证,这种身份证是唯一的。一般来说,只要有服务器端的证书就可以了,但是有时需要客户端提供自己的证书,已证明其身份。
一般证书可以使用权威机构颁发的证书,如:veri sign,百度使用的就是veri sign颁发的证书,这样的权威证书机构是受信任的,但是这些机构颁发的证书往往是需要收费的,这样的证书也难得到。对于小型企业来说为了节约成本,常常使用自签名的证书。
接下来使用JDK keytool工具来签发证书,如果未安装JDK,请先安装JDK(本文使用的是JDK7)。本文所有的证书文件都放到F:\ca,您可以选择一个目录来存放。
keytool -genkeypair -v -alias server -keyalg RSA -validity 3650 -keystore ./server.keystore -storepass 123456 -keypass 123456 -dname "CN=127.0.0.1,OU=rm,O=rm,L=gz,ST=gd,C=cn"
注意:-dname参数中的CN应该为服务器所在的ip或者域名
2. 导出服务器端证书
keytool -exportcert -alias server -keystore ./server.keystore -file ./server.cer -storepass 123456
3. 将服务器端证书导入信任证书
keytool -importcert -alias serverca -keystore ./server_trust.keystore -file ./server.cer -storepass 123456
keytool -genkeypair -v -alias client -dname "CN=rorymo" -keyalg RSA -validity 3650 -keypass 123456 -keystore ./client.p12 -storepass 123456 -storetype PKCS12
2. 导出客户端证书
keytool -exportcert -alias client -file ./client.cer -keystore ./client.p12 -storepass 123456 -storetype PKCS12
3. 导入客户端证书到服务器端信任证书库
keytool -importcert -alias clientca -keystore ./server_trust.keystore -file ./client.cer -storepass 123456
4. 查看服务器端信任证书库的信任证书信息
keytool -list -keystore ./server_trust.keystore -storepass 123456
可以看到信任证书库中已经导入了一张服务器端证书和一张客户端证书
5. 至此我们已经生成了如下的文件
将上图的server.keystore和server_trust.keystore放到tomcat的根目录下,例如我的tomcat目录为:F:\ca\apache-tomcat-7.0.64
2. 配置tomcat
编辑conf/server.xml文件加入如下的配置:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="${catalina.base}/server.keystore" keystorePass="123456" truststoreFile ="${catalina.base}/server_trust.keystore" truststorePass="123456"/>
说明:
3. 编写用来获取客户端证书的servlet
1 package com.rorymo.demo.ssl; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import java.security.cert.X509Certificate; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.annotation.WebServlet; 9 import javax.servlet.http.HttpServlet; 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 13 /** 14 * 15 * SSLServlet 16 * 17 * @author rorymo 18 * @version 1.0 19 */ 20 @WebServlet("/SSLServlet") 21 public class SSLServlet extends HttpServlet { 22 23 private static final long serialVersionUID = 1601507150278487538L; 24 private static final String REQUEST_ATTR_CERT = "javax.servlet.request.X509Certificate"; 25 private static final String CONTENT_TYPE = "text/plain;charset=UTF-8"; 26 private static final String DEFAULT_ENCODING = "UTF-8"; 27 private static final String SCHEME_HTTPS = "https"; 28 29 public void doGet(HttpServletRequest request, HttpServletResponse response) 30 throws ServletException, IOException { 31 response.setContentType(CONTENT_TYPE); 32 response.setCharacterEncoding(DEFAULT_ENCODING); 33 PrintWriter out = response.getWriter(); 34 X509Certificate[] certs = (X509Certificate[]) request.getAttribute(REQUEST_ATTR_CERT); 35 if (certs != null) { 36 int count = certs.length; 37 out.println("共检测到[" + count + "]个客户端证书"); 38 for (int i = 0; i < count; i++) { 39 X509Certificate cert = certs[i]; 40 out.println("客户端证书 [" + cert.getSubjectDN() + "]: "); 41 out.println("证书是否有效:" + (verifyCertificate(cert) ? "是" : "否")); 42 out.println("证书详细信息:\r" + cert.toString()); 43 } 44 } else { 45 if (SCHEME_HTTPS.equalsIgnoreCase(request.getScheme())) { 46 out.println("这是一个HTTPS请求,但是没有可用的客户端证书"); 47 } else { 48 out.println("这不是一个HTTPS请求,因此无法获得客户端证书列表 "); 49 } 50 } 51 out.close(); 52 } 53 54 public void doPost(HttpServletRequest request, HttpServletResponse response) 55 throws ServletException, IOException { 56 doGet(request, response); 57 } 58 59 /** 60 * 61 * 校验证书是否过期 62 * 63 * 64 * @param certificate 65 * @return 66 */ 67 private boolean verifyCertificate(X509Certificate certificate) { 68 boolean valid = true; 69 try { 70 certificate.checkValidity(); 71 } catch (Exception e) { 72 e.printStackTrace(); 73 valid = false; 74 } 75 return valid; 76 } 77 78 }
4. 在web应用的web.xml中加入如下配置
<security-constraint> <web-resource-collection> <web-resource-name>SSL</web-resource-name> <url-pattern>/SSLServlet</url-pattern> </web-resource-collection> <user-data-constraint> <description>SSL required</description> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
说明:
由于我们这里是双向认证,所以也需要客户端的证书,我们接下来导入客户端证书:
2. 重新访问上面的地址:http://127.0.0.1:8080/SSL/SSLServlet
浏览器提示选择客户端证书进行认证,我们点击【确定】,打开了一个警告页面,提示我们服务端证书不受信任
而且地址栏的图标有个小红叉:
当然我们直接点击是能打开的
为了不出现这样的警告信息,我们可以导入服务器端证书到客户端
a. 导入服务器端证书到客户端
b. 关闭浏览器,我们再访问
【完】
感谢您的阅读
标签:
原文地址:http://www.cnblogs.com/SiLuoSai/p/tomcat_SSL.html