https双向认证

一、https双向认证原理

双向认证流程

  1. 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务端;
  2. 服务器端将本机的公钥证书(server.crt)发送给客户端;
  3. 客户端读取公钥证书(server.crt),取出了服务端公钥;
  4. 客户端将客户端公钥证书(client.crt)发送给服务器端;
  5. 服务器端使用根证书(root.crt)解密客户端公钥证书,拿到客户端公钥;
  6. 客户端发送自己支持的加密方案给服务器端;
  7. 服务器端根据自己和客户端的能力,选择一个双方都能接受的加密方案;
  8. 使用客户端的公钥加密. 后发送给客户端;
  9. 客户端使用自己的私钥解密加密方案,生成一个随机数R,使用服务器公钥加密后传给服务器端;
  10. 服务端用自己的私钥去解密这个密文,得到了密钥R
  11. 服务端和客户端在后续通讯过程中就使用这个密钥R进行通信了。

双向认证的目的主要是使得双方最终可以安全的得到秘钥R,后面所有传输都是通过秘钥R加密HTTPS双向认证,不仅仅需要用户浏览器校验服务器数字证书,还需要服务器端验证用户是否是可信的。

二、证书生成

如果要把整个双向认证的流程跑通,最终需要8个证书文件:

  • 根证书:root.crt
  • 服务器端公钥证书:server.crt
  • 服务器端私钥文件:server.key;
  • 客户端公钥证书:client.crt
  • 客户端私钥文件:client.key
  • 客户端集成证书(包括公钥和私钥,用于浏览器访问场景):client.p12
  • 客户端集成证书(包括公钥和私钥,用于Spring客户端访问场景):client.jks
  • 服务端集成证书(包括公钥和私钥,用于Spring服务端):localhost.jks

既然是双向验证,就需要双方的密钥,我们服务端称为server,而客户端称为client

生成这一些列证书之前,我们需要先生成一个CA根证书,然后由这个CA根证书颁发服务器公钥证书和客户端公钥证书。

我们可以全程使用openssl来生成一些列的自签名证书,自签名证书没有听过证书机构的认证,很多浏览器会认为不安全,但我们用来实验是足够的。需要在本机安装了openssl后才能继续本章的实验。

2.1 生成根证书root.crt
shell 复制代码
# 生成根证书私钥
openssl genrsa -out root.key 1024

# 根据私钥创建根证书请求文件,需要输入一些证书的元信息:邮箱、域名等
openssl req -new -out root.csr -key root.key

# 结合私钥和请求文件,创建根证书,有效期10年
openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650

经过上面三个命令行,我们最终可以得到一个签名有效期为10年的根证书root.crt,后面我们可以用这个根证书去颁发服务器证书和客户端证书。

2.2 生成服务端证书server.crtserver.key
shell 复制代码
# 创建服务端私钥
openssl genrsa -out server.key 1024

# 根据私钥生成请求文件
openssl req -new -out server.csr -key server.key

# 结合私钥和请求文件创建服务端证书,有效期10年
openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA ./root.crt -CAkey ./root.key -CAcreateserial -days 3650

如果需要只需要部署服务端证书端话,就可以结束了。拿着server.crt公钥和server.key私钥部署在服务器上,然后解析域名到改服务器指向到IP,证书就部署成功了。

2.3 生成客户端证书client.crtclient.key

如果需要做双向验证的,也就是服务端要验证客户端证书的情况。那么需要在同一个根证书下再生成一个客户端证书。

shell 复制代码
# 生成私钥
openssl genrsa -out client.key 1024

# 申请请求文件
openssl req -new -out client.csr -key client.key

# 生成证书
openssl x509 -req -in client.csr -out client.crt -signkey client.key -CA ./root.crt -CAkey ./root.key -CAcreateserial -days 3650
2.4 生成客户端PKCS12
shell 复制代码
# 生成客户端集成证书pkcs12格式的文件,方便浏览器或者http客户端访问(密码:123456)
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
2.5 生成JKS

Springboot项目中我们一般使用jks格式的文件:

shell 复制代码
openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12

keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass 123456 -alias server -deststorepass 123456 -destkeypass 123456 -destkeystore localhost.jks

keytool -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass 123456 -alias server -deststorepass 123456 -destkeypass 123456 -destkeystore client.jks
2.6 注意

根证书的Common Name填写root就可以,客户端和服务器端的证书这个字段需要填写域名,一定要注意的是,根证书的这个字段和客户端证书、服务器端证书不能一样。

三、 程序配置

3.1 Springboot整合双向验证
shell 复制代码
server:
  ssl:
    enabled: false
    key-store-type: JKS
    key-store: localhost.jks
    key-store-password: 123456
    key-alias: localhost
    client-auth: need
    trust-store: localhost.jks
    trust-store-type: JKS
    trust-store-provider: SUN
    trust-store-password: 123456
3.2 Nginx配置

有了上面的一些列证书,我们可以在Nginx服务器上配置双向认证的HTTPS服务了,具体配置方式如下:

shell 复制代码
server {
        listen       3001 ssl;
        server_name  www.yourdomain.com;
        ssl                  on;  
        ssl_certificate      /data/sslKey/server.crt;  #server公钥证书
        ssl_certificate_key  /data/sslKey/server.key;  #server私钥
        ssl_client_certificate /data/sslKey/root.crt;  #根证书,可以验证所有它颁发的客户端证书
        ssl_verify_client on;  #开启客户端证书验证  

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

具体就是将服务器端的两个证书文件(server.crt/server.key)和根证书文件(root.crt)的路径配置到nginxserver节点配置中,并且把ssl_verify_client这个参数设置为on

有一点需要注意的就是,如果客户端证书不是由根证书直接颁发的,配置中还需要加一个配置:ssl_verify_depth 1.

配置完成后,执行nginx -s reload重新加载下就生效了。

3.3 使用curl作为客户端调用验证

使用curl加上证书路径,可以直接测试NginxHTTPS双向认证是否配置成功。下面我们测试三个用例:

  • 使用client.crt/client.key这一套客户端证书来调用服务器端;
  • 不使用证书来调用服务器端
3.3.1 携带证书

带证书的成功调用:

shell 复制代码
#--cert指定客户端公钥证书的路径
#--key指定客户端私钥文件的路径
#-k不校验证书的合法性,因为我们用的是自签名证书,所以需要加这个参数
#可以使用-v来观察具体的SSL握手过程

curl --cert ./client.crt --key ./client.key https://xxxxxx.com -k -v
3.3.2 无证书
shell 复制代码
curl https://xxxxx.com -k
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/1.17.5</center>
</body>
</html>

使用根证书颁发的客户端证书可以正常发起双向HTTPS认证的调用。没有带客户端证书的调用会被服务器端拒绝服务。

参考文章:

1 HTTPS双向认证指南

2 Https双向验证与Springboot整合测试-人来人往我只认你

3 SSL/TLS 双向认证(一) -- SSL/TLS 工作原理

4 Nginx证书配置:tomcat证书jks文件转nginx证书.cetkey文件

5 自签SSL证书以及https的双向认证

相关推荐
曦夜日长3 分钟前
Linux系统篇,进程概念(三):进程状态详解、僵尸进程与孤儿进程的深度解析、Slab机制的了解
linux·运维·服务器
liulilittle11 分钟前
为什么采用全局管理缓存及状态:麻将客户端状态管理
服务器·网络·游戏·客户端·异步·mahjong·麻将
酣大智26 分钟前
OSPF引入的直连路由在 ospf 路由表中看不到
网络·ospf
2601_9663771326 分钟前
等保2.0最新标准新增安全数据处理要求后怎么办?等保一体机数据安全模块来助力
运维·网络·安全·等保一体机
BullSmall30 分钟前
window系统上报Cannot assign requested address
网络·功能测试
杨云龙UP1 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败
执念WRD1 小时前
Fastjson 1.2.83 RCE 漏洞利用
网络·安全·网络安全
xixiaoyunya1 小时前
局域网多电脑文件互备:从传统痛点到自动化方案的技术路径
网络·安全
Wang's Blog2 小时前
Java框架快速入门: Spring Security+OAuth2之搭建授权服务器(依赖与表结构)
java·服务器·spring
Lynne3092 小时前
为什么工业数据越来越需要在现场处理?边缘计算正在解决什么问题?
网络·数据分析·数据