tomcat配置SSL双向认证
一、SSL简单介绍
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. 至此我们已经生成了如下的文件

四、配置tomcat和web应用
- 将证书文件放到tomcat根目录下
将上图的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"/>
说明:
- clientAuth为true表示开启SSL双向认证
- keystoreFile指定服务器端的证书位置
- truststoreFile指定服务器端信任证书库
3. 编写用来获取客户端证书的servlet
package com.rorymo.demo.ssl; import java.io.IOException;
import java.io.PrintWriter;
import java.security.cert.X509Certificate; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
*
* SSLServlet
*
* @author rorymo
* @version 1.0
*/
@WebServlet("/SSLServlet")
public class SSLServlet extends HttpServlet { private static final long serialVersionUID = 1601507150278487538L;
private static final String REQUEST_ATTR_CERT = "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(REQUEST_ATTR_CERT);
if (certs != null) {
int count = certs.length;
out.println("共检测到[" + count + "]个客户端证书");
for (int i = 0; i < count; i++) {
X509Certificate cert = certs[i];
out.println("客户端证书 [" + cert.getSubjectDN() + "]: ");
out.println("证书是否有效:" + (verifyCertificate(cert) ? "是" : "否"));
out.println("证书详细信息:\r" + cert.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);
} /**
*
* 校验证书是否过期
*
*
* @param certificate
* @return
*/
private boolean verifyCertificate(X509Certificate certificate) {
boolean valid = true;
try {
certificate.checkValidity();
} catch (Exception e) {
e.printStackTrace();
valid = false;
}
return valid;
} }
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>
说明:
- 如果不加入这个配置,那么所有访问的地址都必须要使用SSL才能访问,有时我们可能只需要通过某个或者某些SSL地址获取客户端证书来认证用户身份,认证成功后不需要使用SSL来进行访问。(可以配置多个security-constraint)
- url-pattern:指定需要SSL才能进行访问的地址
- transport-guarantee:合法值为NONE、 INTEGRAL或CONFIDENTIAL,transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL
- 创建SSLServlet获取客户端证书
五、测试
- 用浏览器访问http://127.0.0.1:8080/SSL/SSLServlet,细心的读者可能发现链接已经跳转到了https://127.0.0.1:8443/SSL/SSLServlet ,这是由于这个地址被设置为需要SSL才能访问,所以跳转到了这个地址。访问时页面提示如下:

由于我们这里是双向认证,所以也需要客户端的证书,我们接下来导入客户端证书:
- 双击client.p12

- 点击下一步

- 一直点击下一步直到完成证书安装(按照提示进行操作即可)
- 查看安装的客户端证书,由于我使用的Google Chrome浏览器(其他浏览器可能不同),设置 -> 高级设置 -> 管理证书


2. 重新访问上面的地址:http://127.0.0.1:8080/SSL/SSLServlet

浏览器提示选择客户端证书进行认证,我们点击【确定】,打开了一个警告页面,提示我们服务端证书不受信任

而且地址栏的图标有个小红叉:

当然我们直接点击是能打开的

为了不出现这样的警告信息,我们可以导入服务器端证书到客户端
a. 导入服务器端证书到客户端
- 双击server.cer

- 点击安装证书,然后选择证书的存储位置“受信任的根证书颁发机构”,一直点击下一步直到完成

- 查看我们安装的服务器端证书

b. 关闭浏览器,我们再访问
六、附录
- Keytool命令常用参数说明:
- -genkeypair在用户主目录中创建一个默认文件”.keystore”,还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书(在没有指定生成位置的情况下,keystore会存在用户系统默认目录)
- -alias 产生别名 每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写
- -keystore 指定密钥库的路径(产生的各类信息将不在.keystore文件中)
- -keyalg 指定密钥的算法 (如 RSA,DSA,默认值为:DSA)
- -validity 指定创建的证书有效期多少天(默认 90)
- -keysize 指定密钥长度 (默认 1024
- -storepass 指定密钥库的密码(获取keystore信息所需的密码)
- -keypass 指定别名条目的密码(私钥的密码)
- -dname 指定证书发行者信息 其中: “CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码”
- -list 显示密钥库中的证书信息如:keytool -list -v –keystore path/to/keystore -storepass password
- -v 显示密钥库中的证书详细信息
- -exportcert 导出指定别名的证书,如:keytool - exportcert -alias theAlias -keystore path/to/keystore -file path/to/keystore/cert -storepass pass
- -file 参数指定导出到文件的文件名
- -delete 删除密钥库中某条目 keytool -delete -alias theAlias -keystore path/to/keystore –storepass pass
- -printcert 控制台打印证书的详细信息,如:keytool -printcert -file path/to/keystore/cert -v
- -keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias theAlias -keypass oldPass -new newPass -storepass keystorePass -keystore path/to/keystore
- -storepasswd 修改keystore口令 keytool -storepasswd -keystore path/to/keystore -storepass oldPass -new newPass
- -importcert 将已签名数字证书导入密钥库 keytool -importcert -alias certAlias -keystore path/to/keystore -file path/to/keystore/cert
2. 本文源码下载
【完】
感谢您的阅读
tomcat配置SSL双向认证的更多相关文章
- Tomcat 配置 HTTPS双向认证
Tomcat 配置 HTTPS 双向认证指引说明: � 本文档仅提供 Linux 操作系统下的指引 � 在阅读本指引前请您在 Linux 部署 JDK 和 Tomcatserver为了 Tomcat ...
- NGINX 配置 SSL 双向认证
对于 NGINX 的 HTTPS 配置,通常情况下我们只需要实现服务端认证就行,因为浏览器内置了一些受信任的证书颁发机构(CA),服务器端只需要拿到这些机构颁发的证书并配置好,浏览器会自己校验证书的可 ...
- TOMCAT配置SSL认证为HTTPS协议服务
1 . 问题概述 很多安全性要求较高的系统,都会使用安全套接字层(SSL)进行信息交换, Sun为了解决在Internet上的实现安全信息传输的解决方案.它实现了SSL和TSL(传输层安全)协议 ...
- linux下Tomcat+OpenSSL配置单向&双向认证(自制证书)
背景 由于ios将在2017年1月1日起强制实施ATS安全策略,所有通讯必须使用https传输,本文只针对自制证书,但目前尚不确定自制证书是否能通过appstore审核. 1.必须支持传输层安全(TL ...
- Keytool配置 Tomcat的HTTPS双向认证
Keytool配置 Tomcat的HTTPS双向认证 证书生成 keytool 简介 Keytool是一个Java数据证书的管理工具, Keytool将密钥(key)和证书(certificates) ...
- apache用户认证,ssl双向认证配置
安装环境: OS:contos 6.4 httpd:httpd-2.2.15-59.el6.centos.i686.rpm openssl:openssl-1.0.1e-57.el6.i686.rpm ...
- nginx支持ssl双向认证配置
nginx支持ssl双向认证配置 listen 443; server_name test.com; ssl on; ssl_certificate server.crt; //server端公钥 s ...
- SSL双向认证(高清版)
介绍了SSL双向认证的一些基本问题,以及使用Nginx+PHP基于它搭建https的Webservice. 之前的方式只是实现1:1的模式,昨天同事继续实现了n:1的模式,这里我再整理记录下. 由于n ...
- Nginx、SSL双向认证、PHP、SOAP、Webservice、https
本文是1:1模式,N:1模式请参见新的一篇博客<SSL双向认证(高清版)> ----------------------------------------------------- 我是 ...
随机推荐
- 设置Textview最大长度,超出显示省略号
<TextView android:id="@+id/tvUserNameUgcListItem" android:layout_height="@dimen/dp ...
- iOS阶段学习第34天笔记(UI小组件 UISegment-UISlider-UIStepper-UIProgressView-UITextView介绍)
iOS学习(UI)知识点整理 一.UI小组件 1.UISegmentedControl 分段选择器 实例代码 - (void)viewDidLoad { [super viewDidLoad]; / ...
- T- SQL性能优化详解
摘自:http://www.cnblogs.com/Shaina/archive/2012/04/22/2464576.html 故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册 ...
- ASP.NET5,MVC 6,Beta 7与VS 2015 RTM的兼容问题
温馨提示:本文杂而乱,最终不知所云. Visual Studio 2015 RTM已经于2015年7月20号正式发布,我也在第一时间下载安装了起来. 虽然在5月份就开始使用RC版本,但是还是很期待正式 ...
- img在div中居中的问题
Img是内联元素,要设置其margin属性使其居中,就要将其转换为块元素display:block;然后利用margin:0 auto;实现图片的水平居中:(有的设计师为图片再加个div标签,然后通过 ...
- luogg_java学习_12_线程
本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! 线程 程序.进程.线程的概念 程序:我们用程序设计语言 ...
- Java入门第一章
后天就是十一长假了,亲们准备好了去哪儿玩了吗? 今天有点空,就来聊聊Java吧,当然是一些Java入门知识了,网上有很多,这里我只是列举一些我自己学到的,感谢大家关注喵的博客这么久,也为大家带来点新知 ...
- hdu-1179-二分图最大匹配
Ollivanders: Makers of Fine Wands since 382 BC. Time Limit: 2000/1000 MS (Java/Others) Memory Lim ...
- C语言: 预处理
1. 字符映射 键盘有多种标准规格,例如常用的IBM 104键盘标准,然而不是所有键盘都能打出像#这样的符号,因此C语言的预处理引入了字符映射机制.如果程序员要求,预处理会按照约定对源代码中的字符进行 ...
- MySQL中优化sql语句查询常用的30种方法
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使 ...