Https双向验证与Springboot整合测试-人来人往我只认你
1 简介
不知不觉Https相关的文章已经写了6篇了,本文将是这个专题的最后一篇,起码近期是最后一篇。前面6篇讲的全都是单向的Https验证,本文将重点介绍一下双向验证。有兴趣的同学可以了解一下之前的文章:
(0)Https专题
(2)HTTPS之密钥知识与密钥工具Keytool和Keystore-Explorer
(3)Springboot以Tomcat为容器实现http重定向到https的两种方式
(4) Springboot以Jetty为容器实现http重定向到https
(5)nginx开启ssl并把http重定向到https的两种方式
(6)Springboot-WebFlux实现http重定向到https
双向验证是比较难的,能掌握双向验证,单向验证就没什么问题了。
2 单向验证与双向验证
2.1 概念和作用
所谓单向验证(One Way SSL),就是只有一方验证另一方是否合法,通常是客户端验证服务端。比如我们打开www.pkslow.com 这个网站,服务端不会验证客户端,只要你来我就欢迎。但客户端不一样,浏览器会验证这个网站是不是安全的,一般是通过CA颁发的SSL证书来验证。

而双向验证(Two Way SSL)则不同。不仅客户端需要验证服务端,服务端同样戒备心很重,也需要验证客户端是否是合法。

大家是否会有疑问,这么麻烦的双向验证有什么用?我们平常用单向验证不就已经足够了吗?单向验证虽然安全,但不够安全,使用双向验证可以只让特定的客户端访问,安全性会高一点。
另一方面,如果服务端没有做账户权限控制,但又想只限制特定的客户端访问,双向验证就非常有用,我只验证我相信的客户端,其它一概拒绝!这样即使我的服务暴露在网上,也不怕别人访问。既保证了安全,又省去了做权限控制的麻烦。
2.2 验证合法性
验证合法性通常是通过Trust Store。要求要把对方的cert装在自己的Trust Store里。
这就衍生出了一个之前没有讲过的概念:Trust Store。密钥文件可以存放私钥和公钥,具体一点来说是可以存放自己的私钥、自己的公钥和别人的公钥(也可以存放别人的私钥,但这不合理,私钥必须私有)。一般地我们把自己的(私钥和公钥)存放在Key Store里,而把别人的公钥存放在Trust Store里。

以Java程序为例,我们建立SSLContext时,需要生成KeyManager和TrustManager,对应的参数为javax.net.ssl.keyStore和javax.net.ssl.trustStore。而它们的作用正好体现了不同Store的作用:
TrustManager:决定对方来的cert是不是可信的;
KeyManager:决定自己发什么cert给对方。
如果我们不指定TrustStore,默认是$JAVA_HOME/jre/lib/security/cacerts文件。我们可以通过命令查看这个文件都有什么certs:
keytool -list -keystore cacerts
2.3 单向验证的流程
单向验证的流程如下图所示:

建立连接的过程:
客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;
客户端使用服务端返回的信息验证服务器端的合法性,包括:
(1)证书是否过期
(2)颁发服务器证书的CA是否可靠
(3)返回的公钥是否能正确解开返回证书中的数字签名
(4)服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信,否则,终止通信;客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择;
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
服务器将选择好的加密方案通过明文方式返回给客户端;
客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器;
服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
2.4 双向验证的流程
双向验证的流程如下图所示:

建立连接的过程:
客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;
客户端使用服务端返回的信息验证服务器端的合法性,包括:
(1)证书是否过期
(2)颁发服务器证书的CA是否可靠
(3)返回的公钥是否能正确解开返回证书中的数字签名
(4)服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信,否则,终止通信;服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端;
验证客户端的证书,通过验证后,会获得客户端的公钥;
客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择;
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
将加密方案通过使用之前获取到的公钥进行加密,返回给客户端;
客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端;
服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
3 Springboot整合双向验证
理论知识讲完了,就来实战一下,Springboot是怎么整合双向验证的。
3.1 生成密钥文件
既然是双向验证,就需要双方的密钥,我们服务端称为localhost,而客户端称为client。需要生成双方的密钥文件,并把对方的cert导入自己的密钥文件里。整个过程如下:
注意:密码统一为changeit。
# 生成服务端密钥文件localhost.jks
keytool -genkey -alias localhost -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore localhost.jks -dname CN=localhost,OU=Test,O=pkslow,L=Guangzhou,C=CN -validity 731 -storepass changeit -keypass changeit
# 导出服务端的cert文件
keytool -export -alias localhost -file localhost.cer -keystore localhost.jks
# 生成客户端的密钥文件client.jks
keytool -genkey -alias client -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore client.jks -dname CN=client,OU=Test,O=pkslow,L=Guangzhou,C=CN -validity 731 -storepass changeit -keypass changeit
# 导出客户端的cert文件
keytool -export -alias client -file client.cer -keystore client.jks
# 把客户端的cert导入到服务端
keytool -import -alias client -file client.cer -keystore localhost.jks
# 把服务端的cert导入到客户端
keytool -import -alias localhost -file localhost.cer -keystore client.jks
# 检验服务端是否具有自己的private key和客户端的cert
keytool -list -keystore localhost.jks
成功执行完上述步骤后,会生成4个文件:
服务端密钥文件: localhost.jks
服务端cert文件:localhost.cer
客户端密钥文件:client.jks
客户端cert文件:client.cer
实际上cert文件可以不要了,因为已经导入对方的Trust Store里面去了。也就是在文件localhost.jks里,包含了服务端的私钥、公钥还有客户端的公钥。client.jks同理。
3.2 配置Spirngboot
Springboot的配置文件如下:
server.port=443
server.ssl.enabled=true
server.ssl.key-store-type=JKS
server.ssl.key-store=classpath:localhost.jks
server.ssl.key-store-password=changeit
server.ssl.key-alias=localhost
server.ssl.trust-store=classpath:localhost.jks
server.ssl.trust-store-password=changeit
server.ssl.trust-store-provider=SUN
server.ssl.trust-store-type=JKS
server.ssl.client-auth=need
需要分别配置Key Store和Trust Store的文件、密码等信息,即使是同一个文件。
需要注意的是,server.ssl.client-auth有三个可配置的值:none、want和need。双向验证应该配置为need;none表示不验证客户端;want表示会验证,但不强制验证,即验证失败也可以成功建立连接。
3.3 用Postman测试双向验证
完成密钥文件准备和配置后,启动Springboot便可以了。这里用Postman访问如下:

无法建立https连接,无法访问。原因就是Postman作为客户端并没有合法的cert。
为了建立连接,应该要把客户端的密钥文件给Postman使用。因为JKS是Java的密钥文件格式,我们转换成通用的PKCS12格式如下:
# 转换JKS格式为P12
keytool -importkeystore -srckeystore client.jks -destkeystore client.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass changeit -deststorepass changeit -srckeypass changeit -destkeypass changeit -srcalias client -destalias client -noprompt
把客户端密钥文件配置到Postman如下图所示:

再重新访问,成功了!

或者我们可以把密钥文件拆成private key和cert,命令如下:
# 导出客户端的cert文件
openssl pkcs12 -nokeys -in client.p12 -out client.pem
# 导出客户端的key文件
openssl pkcs12 -nocerts -nodes -in client.p12 -out client.key
把客户端的密钥文件配置到Postman上,如图所示:

结果一样是可以成功访问:

3.4 用curl命令测试
没有安装Postman怎么办呢?还好,用强大的curl命令也是可以测试的。命令如下:
curl -k --cert client.pem --key client.key https://localhost/hello
# 下面命令可以查看建立SSL连接详情
curl -v -k --cert client.pem --key client.key https://localhost/hello
如果觉得指定两个文件太麻烦,可以只生成一个文件,命令如下:
openssl pkcs12 -nodes -in client.p12 -out client_all.pem
则连接命令变成了:
# 需要指定密码
curl -k --cert client_all.pem:changeit https://localhost/hello
4 总结
这篇文章讲解了单向验证和双向验证的区别及流程,并用实例展示如何实现双向验证,相信跟着做一遍,基本都能理解了。
参考资料:
Trust Store vs Key Store - creating with keytool
An Overview of One-Way SSL and Two-Way SSL
验证流程部分来自:Https单向认证和双向认证
欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章!
欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

多读书,多分享;多写作,多整理。
Https双向验证与Springboot整合测试-人来人往我只认你的更多相关文章
- linux:Nginx+https双向验证(数字安全证书)
本文由邓亚运提供 Nginx+https双向验证 说明: 要想实现nginx的https,nginx必须启用http_ssl模块:在编译时加上--with-http_ssl_module参数就ok.另 ...
- nginx配置https双向验证(ca机构证书+自签证书)
nginx配置https双向验证 服务端验证(ca机构证书) 客户端验证(服务器自签证书) 本文用的阿里云签发的免费证书实验,下载nginx安装ssl,文件夹有两个文件 这两个文件用于做服务器http ...
- Java Https双向验证
CA: Certificate Authority,证书颁发机构 CA证书:证书颁发机构颁发的数字证书 参考资料 CA证书和TLS介绍 HTTPS原理和CA证书申请(满满的干货) 单向 / 双向认证 ...
- .net core https 双向验证
文章来自:https://www.cnblogs.com/axzxs2001/p/10070562.html 关于https双向认证的知识可先行google,这时矸接代码. 为了双向认证,我们首先得准 ...
- soapui测试https双向验证p12项目
1.准备好p12 和jsk秘钥文件 2.配置soapui ssl 其中: 1:jks就是放在trustStore那里,密码填写为 106075 2:p12放到keystore,密码填写:180000 ...
- ssl/https双向验证的配置
1.SSL认证 不需要特别配置,相关证书库生成看https认证中的相关部分 2.HTTPS认证 一.基本概念 1.单向认证,就是传输的数据加密过了,但是不会校验客户端的来源 2.双向认证,如果客户端 ...
- ssl https双向验证的配置与证书库的生成
1.SSL认证 不须要特别配置,相关证书库生成看https认证中的相关部分 2.HTTPS认证 一.基本概念 1.单向认证,就是传输的数据加密过了,可是不会校验client的来源 2.双向认证,假设 ...
- https 双向验证
服务器配置 服务器秘钥 服务器公钥证书 ,客户端公钥证书 客户端配置 客户端秘钥+密码 服务器公钥证书 目前android验证ok,pc浏览器添加客户端秘钥证书 ,访问还是失败,待继续查找资 ...
- HTTPS实战之单向验证和双向验证
转载自:https://mp.weixin.qq.com/s/UiGEzXoCn3F66NRz_T9crA 原创: 涛哥 coding涛 6月9日 作者对https 解释的入目三分啊 (全文太长,太懒 ...
随机推荐
- sparkSessiontest
记事本内容: 打印结构: 方法1: object SparkSessionTest { case class Person(name:String,age:Int) def main(args: Ar ...
- lr 遇到的问题
1.Abnormal termination, caused by mdrv process termination 解决方法:修改LR中的D:\Program Files\Mercury\LoadR ...
- python字符串列表元组序列操作
Table of Contents generated with DocToc python系列-字符串.列表.元组的操作 序列的访问及运算符 序列通用操作 访问单个元素 切片访问一部分元素 序列的复 ...
- VulnHub靶场学习_HA: Avengers Arsenal
HA: Avengers Arsenal Vulnhub靶场 下载地址:https://www.vulnhub.com/entry/ha-avengers-arsenal,369/ 背景: 复仇者联盟 ...
- sublime text3配置html环境
1.安装View in Browser 2.配置快捷键 [1]Preferences—Key Bindings—User. [2]插入代码 [ //ie { "keys": [&q ...
- 搞懂 XML 解析,徒手造 WEB 框架
恕我斗胆直言,对开源的 WEB 框架了解多少,有没有尝试写过框架呢?XML 的解析方式有哪些?能答出来吗?! 心中没有答案也没关系,因为通过今天的分享,能让你轻松 get 如下几点,绝对收获满满. a ...
- vue中的ref属性
1.什么是ref? ref是用于快速定位到dom结构,vue中一般不去操作dom结构,他是数据驱动的.jQuery会疯狂操作DOM {{msg}} mounted(){ let h = this.$r ...
- python 异步 I/O
如果你想了解异步编程,那么必然会涉及出许多相关概念. 堵塞/非堵塞 同步/异步 多进程/多线程/协程 为什么我要学习这个话,因为我想搞懂异步框架和异步接口的调用.所以,我的学习路线是这样的: 1.py ...
- C++创建动态库
[C++]创建动态库 有很多方法,这个只是其中一种 比较简洁的方法. char* __stdcall correction(char* str) char *_result = new char[se ...
- 常问的MySQL面试题整理
char.varchar 的区别是什么? varchar是变长而char的长度是固定的.如果创建的列是固定大小的,你会得到更好的性能 truncate 和 delete 的区别是什么? delete ...