实现在 Linux 下 Tomcat 的双向SSL认证-程序员宅基地

技术标签: java  web.xml  操作系统  

实现在 Linux 下 Tomcat 的双向SSL认证

 

一、前言:

  关于如何使用Tomcat服务器实现双向SSL认证的文章很早就有了, 比较实用的文章可以看看 IBM developerWorks 中国网站 2002年5月 配置Tomcat 4使用双向SSL(http://www-900.ibm.com/developerWorks/cn/security/se-tcssl/index.shtml )以及 配置Tomcat 5使用双向SSL (http://thinkbase.net/w/main/Wiki?Tomcat5SSL_ServerAndClient)。

      关于原理方面不是本文的重点,故下面只讲解实际操作的过程以及每个过程的说明:


二、需要的软件包:

       Tomcat 5.0.25
       用途:Web Server。 
      下载: http://jakarta.apache.org/builds/jakarta-tomcat-5.0/release/v5.0.25/bin/

       JSSE 1.0,2 
       用途:用来产生Tocmcat使用的秘钥对(keystore)。 在 JDK 1.4以上版本 中已经自带了这个工具, 因此, 只需要安装 JDK1.4.x 即可 
       下载: http://java.sun.com/products/jsse/

       Openssl 0.9.9.6 
       用途:用来产生CA证书、签名并生成IE可导入的PKCS#12格式私钥。 
       下载: http://www.openssl.org/

       以上工具的安装过程可以参考自带的帮助,本文就不再详细描述了。


三、证书环境设置:

export CA_DN=/C=CN/ST=GuangDong/L=GuangZhou/O=boss ssl/OU=Boss CACenter/CN=Boss CA Root/[email protected]

export SERVER_DNAME=CN=21cn.com,OU=Boss Server,O=boss ssl,L=GuangZhou,ST=GuangDong,C=CN
export SERVER_KEYPASS=openssl
export SERVER_STOREPASS=openssl
export SERVER_ALIAS=boss-alias
export SERVER_KEYSTORE=boss-alias.keystore

export CLIENT_DN_OU=W21cn-boss-client
export CLIENT_DN_CN=Huronghua
export CLIENT_DN=/C=CN/O=W21cn Boss/OU=$CLIENT_DN_OU/CN=$CLIENT_DN_CN

export SSL_JAVA_HOME=/home/uud/software/jdk1.5.0_06
export JDK_KEYSTORE=$SSL_JAVA_HOME/jre/lib/security/cacerts

#JSSE 信任的CA根证书的存储密码, 似乎不能改变
export JDK_STOREPASS=changeit

export OPENSSL_SRL_FILE=./ca-cert.srl
export CA_ROOT_ALIAS=Boss-CA-ROOT


四、生成CA私钥以及自签名根证书, 最后得到PKCS12格式的CA根证书: 

说明:
该命令生成CA私钥以及自签名根证书, 最后得到PKCS12格式的CA根证书(PKCS12格式的CA根证书受密码保护, 因此有比较好的安全性); 
生成的PKCS12格式的CA根证书保存在 dist\ca-cert 目录下, 在正式使用的系统中, 这个证书文件(*.pfx)需要妥善保存, 
因为以后的服务器证书和客户端证书都需要依赖这个证书, 尤其是客户端证书, 如果丢失了CA根证书, 
就无法发布新的客户端证书了, 而重新生成CA根证书, 则需要重新生成服务器证书和客户端证书, 
在客户端用户较多的情况下, 重新发布所有的客户端证书是有相当大的工作量; 
在执行这个命令的过程中, 会提示输入证书保护密码, 请注意不要遗忘或者泄漏这个密码, 否则根证书的安全会受到威胁. 

mkdir ca
mkdir dist
cd dist
mkdir ca-cert
cd ..


# genrsa [产生密钥命令] -out[密钥文件输出路径] 1024 [密钥位数]
openssl genrsa -out ca/ca-key.pem 1024

# req[产生证书命令] -new[新生成] -out[证书文件输出路径] -key[私钥文件路径]

openssl req -new -out ca/ca-req.csr -key ca/ca-key.pem -subj $CA_DN

# x509[签发x509证书命令] -req[输入待签发证书] -in[输入待签发证书文件路径] -out[产生x509证书文件输出路径]
# -signkey[自签发密钥文件路径] -days[证书有效期]
openssl x509 -req -in ca/ca-req.csr -out ca/ca-cert.pem -signkey ca/ca-key.pem -days 365

# 生成CA证书: ca/ca-cert.pfx, 注意一定要记住导出密码:默认为 ssl
# pkcs12[生成PKCS12格式证书命令] -export[导出文件] -clerts[仅导出client证书] -password[导出密码]
# -in[输入的client证书文件路径] -inkey[client证书密钥文件路径] -out[导出PKS12格式文件路径]

openssl pkcs12 -export -clcerts -in ca/ca-cert.pem -inkey ca/ca-key.pem -out ca/ca-cert.pfx

# 将生成的证书保存起来(以后需要用到)
cp ca/ca-cert.pfx dist/ca-cert/ca-cert-200606.pfx

      


五、从PKCS12格式的CA根证书导出 CA私钥和未加密CA根证书

说明:
该命令用于从PKCS12格式的CA根证书中导出CA私钥和未加密CA根证书; 
由于安全原因, CA根证书平时以密码保护的PKCS12格式文件(*.pfx)存放, 
那么如果需要使用CA根证书来发布服务器证书或者客户端证书时, 首先需要执行这个命令得到CA根证书的未加密形式; 
在执行这个命令的过程中, 会出现两次提示输入根证书的保护密码, 如果密码不正确, 这个命令将不能执行成功, 
也就无法进行下面两步的发布证书的操作了.

mkdir decrypt_ca

# 从PKCS12格式的CA证书导出不加密的CA证书: ca\ca-cert.pem
openssl pkcs12 -in dist/ca-cert/ca-cert-20060621.pfx -clcerts -nodes -nokeys -out decrypt_ca/ca-cert.pem

# 将得到的证书文件的开头四行(Bag Attributes)去掉
# 因为step2-server.bat中keytool import时会认为含有Bag Attributes的文件"不是一个 X.509 认证"

vi ca-cert.pem 
先按 4,再按 dd
最后按 x! 退出文件编辑

# 从PKCS12格式的CA证书导出CA私钥: ca\ca-key.pem
openssl pkcs12 -in dist/ca-cert/ca-cert-20060621.pfx -clcerts -nodes -out decrypt_ca/file.pem
openssl rsa -in decrypt_ca/file.pem -out decrypt_ca/ca-key.pem

   


六、生成服务器端证书

说明:
该命令用于生成服务器端证书(keystore文件); 
注意: CA根证书同时也会被导入到证书的keystore文件中, 这样在将这个证书应用到Tomcat Web服务器上的时候就不需要将CA根证书
导入到JSSE的默认位置了; 
这个命令必须在执行 (五、从PKCS12格式的CA根证书导出 CA私钥和未加密CA根证书) 之后才能正常运行.

生成KeyPair
mkdir server


# -genkey[产生密钥对] -alias[密钥对别名] -validity[密钥有效期] -keyalg[密钥算法参数] -keysize[密钥位数]
# -keypass[密钥保护密码]- storepass[存储密码]
# -dname[别名相关附加信息,其中cn是服务器的名字一定要与WEB服务器中设置的一样] -keystore[密钥存储文件路径]

keytool -genkey -alias $SERVER_ALIAS -validity 720 -keyalg RSA -keysize 1024 -keypass $SERVER_KEYPASS -storepass $SERVER_STOREPASS -dname $SERVER_DNAME -keystore server/$SERVER_KEYSTORE


生成待签名证书 server/server.csr
# -certreq[产生待签名证书] -alias[证书别名] -sigalg[证书算法参数] -file [产生文件输出路径]
# -keypass[密钥保护密码] -keystore[存储文件路径] -storepass[存储密码]

keytool -certreq -alias $SERVER_ALIAS -sigalg MD5withRSA -file server/server.csr -keypass $SERVER_KEYPASS -keystore server/$SERVER_KEYSTORE -storepass $SERVER_STOREPASS


用CA私钥进行签名, 产生x509证书文件

# x509[签发x509证书命令] -req[输入待签发证书] -in[输入待签发证书文件路径] -out[产生x509证书文件输出路径]
# -CA[签发根证书] -CAkey[根证书密钥文件] -days[证书有效期] -CAserial[CA序列号文件]

openssl x509 -req -in server/server.csr -out server/server-cert.pem -CA decrypt_ca/ca-cert.pem -CAkey decrypt_ca/ca-key.pem -days 365 -CAserial $OPENSSL_SRL_FILE -sha1 -trustout


导入(替换)信任的CA根证书到JSSE的默认位置(%JDK_KEYSTORE%)


# 导入前首先删除(如果原来已经导入过)
# JSSE 信任的CA根证书的密钥存储文件路径
keytool -delete -v -alias $CA_ROOT_ALIAS -storepass $JDK_STOREPASS -keystore $JDK_KEYSTORE

# -import[导入命令] -v trustcacerts[导入信任证书] -storepass[存储密码] -alias[CA根证书的别名]
# -file[证书文件路径] -keystore[导入文件路径] -noprompt[不提示"信任这个认证?"]

keytool -import -v -trustcacerts -storepass $JDK_STOREPASS -alias $CA_ROOT_ALIAS -file decrypt_ca/ca-cert.pem -keystore $JDK_KEYSTORE


把CA签名后的server端证书导入keystore: server/%SERVER_KEYSTORE%
# -import[导入命令] -v trustcacerts[导入信任证书] -storepass[存储密码] -keypass[密钥保护密码]
# -alias[服务器证书的别名] -file[证书文件路径] -keystore[导入文件路径]

keytool -import -v -trustcacerts -storepass $SERVER_STOREPASS -keypass $SERVER_KEYPASS -alias $SERVER_ALIAS -file server/server-cert.pem -keystore server/$SERVER_KEYSTORE

把CA根证书导入keystore: server/%SERVER_KEYSTORE%
# -import[导入命令] -v trustcacerts[导入信任证书] -storepass[存储密码] -keypass[密钥保护密码]
# -alias[服务器证书的别名] -file[证书文件路径] -keystore[导入文件路径] -noprompt[不提示"您仍然想要将它添加到自己的keystore 吗?"]

keytool -import -v -trustcacerts -storepass $SERVER_STOREPASS -keypass $SERVER_KEYPASS -alias $CA_ROOT_ALIAS -file decrypt_ca/ca-cert.pem -keystore server/$SERVER_KEYSTORE


查看JSSE CA根证书
keytool -list -storepass $JDK_STOREPASS -keystore $JDK_KEYSTORE -alias $CA_ROOT_ALIAS -v

删除导入到JSSE的默认位置的CA根证书(使JDK恢复原状)
keytool -delete -v -alias $CA_ROOT_ALIAS -storepass $JDK_STOREPASS -keystore $JDK_KEYSTORE


将生成的证书保存起来(供服务器使用)
cd dist
mkdir server
cd ..
cp server/$SERVER_KEYSTORE dist/server/$SERVER_KEYSTORE

查看server端证书
keytool -list -storepass $SERVER_STOREPASS -keystore dist/server/$SERVER_KEYSTORE -v


七、发布客户端证书: 

说明:
这个命令用于发布客户端证书; 
为了便于批量生成客户端证书, 这个命令支持命令行参数, 第1到3个参数依次为: 
客户端证书的名称(Common Name) 
客户端证书所属的组织(Organizational Unit Name) 
产生的PKS12格式客户端证书的导入密码, 这个密码可以保护证书只能被知道密码的用户导入到浏览器
这个命令必须在执行 (五、从PKCS12格式的CA根证书导出 CA私钥和未加密CA根证书) 之后才能正常运行.

mkdir client

cd dist
mkdir client
cd ..

# 生成client私钥: client/client-key.pem
# genrsa [产生密钥命令] -out[密钥文件输出路径] 1024 [密钥位数]

openssl genrsa -out client/client-key.pem 1024


生成待签名证书: client/client-req.csr

# req[产生证书命令] -new[新生成] -out[证书文件输出路径] -key[私钥文件路径]
# -subj[request's subject, 这里放置Distinguished Name(DN)信息]

openssl req -new -out client/client-req.csr -key client/client-key.pem -subj $CLIENT_DN


用CA私钥进行签名, 产生x509证书文件: client/client.crt
# x509[签发x509证书命令] -req[输入待签发证书] -in[输入待签发证书文件路径] -out[产生x509证书文件输出路径]
# -signkey [密钥文件路径]
# -CA[签发根证书] -CAkey[根证书密钥文件] -days[证书有效期] -CAserial[CA序列号文件]

openssl x509 -req -in client/client-req.csr -out client/client.crt -signkey client/client-key.pem -CA decrypt_ca/ca-cert.pem -CAkey decrypt_ca/ca-key.pem -days 365 -CAserial $OPENSSL_SRL_FILE

生成client端的个人证书: client/$_CLIENT_P12_FILE

# pkcs12[生成PKS12格式证书命令] -export[导出文件] -clerts[仅导出client证书] -password[导出密码]
# -in[输入的client证书文件路径] -inkey[client证书密钥文件路径] -out[导出PKS12格式文件路径]
# -name[好记的名字]

密码是 clientssl
openssl pkcs12 -export -clcerts -in client/client.crt -inkey client/client-key.pem -out client/$CLIENT_DN_OU-$CLIENT_DN_CN.p12 -name $CLIENT_DN_OU-$CLIENT_DN_CN

将生成的证书保存起来(发布给用户)
cp client/$CLIENT_DN_OU-$CLIENT_DN_CN.p12 dist/client/$CLIENT_DN_OU-$CLIENT_DN_CN.p12


八、Tomcat 5 服务器配置: 

参考配置方法如下:
将 "六、生成服务器端证书" 命令产生的 dist\server 目录下的 keystore 文件(如果使用默认配置, 这个文件叫做"boss-alias.keystore")复制到 Tomcat 安装目录的 conf 目录下; 
修改 Tomcat 安装目录的 conf 目录下的 "server.xml" 文件, 修改 <Service name="Catalina"> 包含的 "Connector" 元素, 示例如下(仅供参考): 

<Connector port="8443" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
URIEncoding="UTF-8"
keystoreFile="%Tomcat%/conf/boss-alias.keystore"
keystorePass="openssl"
truststoreFile="%Tomcat%/conf/boss-alias.keystore"
truststorePass="openssl"/>


九、启用双向 SSL 时 Web 应用程序的配置 : 

       要启用双向 SSL 认证, 在 Web 应用程序的 web.xml 中需要如下增加一些配置: auth-method=CLIENT-CERT 说明是"以客户端数字证书来确认用户的身份", transport-guarantee=CONFIDENTIAL 表示应用程序要求数据必须在一种"防止其他实体看到传输的内容的方式中传送".. 

<login-config>
<!-- Authorization setting for SSL -->
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
<!-- Authorization setting for SSL -->
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>


十、编写 JSP 页面显示 证书的内容: 

      经过以上的配置之后, 那么即使用户是通过 http 访问 Web 应用程序的, 浏览器也会自动切换到 https 方式并弹出选择客户端证书的对话框.
如何使用客户端证书进行用户验证

        在 web 应用程序中, 可以通过 java 代码从 request 对象中获得, 根据 Servlet Specifications, 使用request.getAttribute("javax.servlet.request.X509Certificate") 就可以得到 https 请求的客户端证书链信息, 其中第一个元素就是客户端证书, 相应的示例代码如下:

<%@ page import="java.security.cert.X509Certificate"%>
<%
//response.sendRedirect("jsp/vpay/input.jsp");
String certSubject = null;
java.security.cert.X509Certificate[] certChain=
(java.security.cert.X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate");
if (null!=certChain){
int len=certChain.length;
if (len>0){
java.security.cert.X509Certificate cert =
(java.security.cert.X509Certificate)certChain[0];
java.security.Principal pSubject = cert.getSubjectDN();
certSubject = pSubject.getName();
}
}
%>
Subject = <%=certSubject%>

 

十一、导入客户端证书并访问 HTTPS 应用: 

       导入客户端证书到浏览器中(双击客户端证书文件 "W21cn-boss-client-Huaronghu.p12" 即可导入 IE)。

      导入完毕后, 启动 Tomcat, 可以看到 http://localhost:8080/index.jsp 内容的访问则会自动切换到 https://localhost:8443 上去了; 同时可以看到, 使用 HTTPS 方式访问时, 客户端证书的 Subject 可以被 jsp 页面获得。

        试着在浏览器里面把导入的证书删除, 你会发现 网站的内容已经不能访问了:


十二、总结: 

      当Web服务器开始正式运行以后, "四、生成CA私钥以及自签名根证书, 最后得到PKCS12格式的CA根证书" 命令是不能再次执行的, 
如果需要重新发布服务器证书, 或者发布新的客户端证书,
在执行 “六、生成服务器端证书” 和 “七、生成客户器端证书” 命令前, 
可以通过 “五、从PKCS12格式的CA根证书导出 CA私钥和未加密CA根证书”重新从保存的PKCS12格式CA根证书中导出CA私钥和未加密CA根证书.

转载于:https://my.oschina.net/zhanghuibo/blog/650403

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chicaishi3429/article/details/100851008

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签