实现在 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

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法