大数跨境
0
0

Nginx | HTTPS 加密传输:客户端与Nginx服务端 SSL 双向认证实践

Nginx | HTTPS 加密传输:客户端与Nginx服务端 SSL 双向认证实践 全栈工程师修炼指南
2025-12-18
2
导读:本文将主要介绍 Nginx 中客户端证书的校验,为了保证数据在传输过程中不被泄露和篡改,且应用间的数据传输敏感的场景之下,通常会采用 SSL 双向认证的方式来进行身份验证,简单来说:服务端需要提供CA

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ]


📢 大家好,我是 WeiyiGeek一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 🚀,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南,转发收藏学习不迷路 😋 。

本地客户端 与 Nginx 服务端 SSL 双向认证指令浅析与配置

描述: 上文《Nginx | 核心知识150讲,百万并发下性能优化之SSL证书签发与HTTPS加密传输实践笔记》,介绍了如何在 Nginx 中配置 HTTPS 服务端单向认证,即证书配置在服务端,客户端不需要提供证书,但是这样的配置方式存在一定的安全隐患,因为客户端与服务端之间的通信并没有进行双向身份验证,有可能存在中间人攻击和数据泄露等问题。因此,为了保证数据在传输过程中不被泄露和篡改,且应用间的数据传输敏感的场景之下,通常会采用 SSL 双向认证的方式来进行身份验证,简单来说:服务端需要提供CA证书来对客户端证书进行身份验证的过程。

图片

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_wwnjk3rmwroa.html

同样的,在 Nginx 中配置客户端与服务端 SSL 双向认证,除开上一小节的指令,也涉及到以下几个指令:

指令参数

  • ssl_client_certificate 指令用于指定具有PEM格式的受信任CA证书签发的客户端证书,若启用了ssl_stapling,则该文件用于验证客户端证书和OCSP响应。
Syntax: ssl_client_certificate file;
Default: —
Context: http, server
  • ssl_trusted_certificate 指令用于指定具有PEM格式的受信任CA证书的文件,该文件用于验证客户端证书,与ssl_client_certificate 设置的证书不同,这些证书的列表不会发送给客户端。
Syntax: ssl_trusted_certificate file;
Default:—
Context: http, server
  • ssl_verify_client 指令用于指定是否启用客户端证书验证,可选值为 off、on 或 optional, 验证结果存储在$ssl_client_verify 变量中。
Syntax: ssl_verify_client on | off | optional | optional_no_ca;
Default: ssl_verify_client off;
Context: http, server

# 参数说明
  on 启用客户端证书验证
  off 禁用客户端证书验证
  optional 请求客户端证书并验证证书是否存在
  optional_no_ca 请求客户端证书,但不要求它由受信任的CA证书签名
  • ssl_verify_depth 指令用于设置客户端证书链中的验证深度,默认值为1。
Syntax: ssl_verify_depth number;
Default: ssl_verify_depth 1;
Context: http, server
  • ssl_ocsp 指令用于启用客户端证书链的OCSP验证,该功能允许服务器在握手期间验证客户端证书的有效性,而不是等到建立连接后才进行。
Syntax: ssl_ocsp on | off | leaf;
Default: ssl_ocsp off;
Context: http, server
# 参数说明
  on 启用客户端证书链的OCSP验证
  off 禁用客户端证书链的OCSP验证
  leaf 只验证客户端证书的签名,不验证整个链

# 示例:
# 若要解析OCSP响应程序主机名,还应指定resolver指令
ssl_verify_client on;
ssl_ocsp          on;
resolver          192.168.;
  • ssl_ocsp_cache 指令设置存储用于OCSP验证的客户端证书状态的该高速缓存的名称和大小。该高速缓存在所有工作进程之间共享。具有相同名称的缓存可以在多个虚拟服务器中使用。
Syntax: ssl_ocsp_cache off | [shared:name:size];
Default: ssl_ocsp_cache off;
Context: http, server
  • ssl_ocsp_responder 指令用于设置客户端证书链的OCSP响应程序的URL,该选项仅在启用ssl_ocsp on;后才有效。如果设置了此参数,则Nginx将尝试从指定的URL获取OCSP响应程序,并将其用作验证客户端证书的有效性的替代方法。
Syntax:  ssl_ocsp_responder url;
Default:  —
Context:  http, server

另外,http_ssl_module 模块还提供了一些内置变量,可用于输出客户端证书中的信息,如下所示:

  • $ssl_server_name: 返回通过SNI(1.7.0)请求的服务器名称;
  • $ssl_alpn_protocol: 返回ALPN在SSL握手期间选择的协议,否则返回空字符串(1.21.4)
  • $ssl_protocol: 返回使用的SSL/TLS协议版本名称(例如,TLSv1.2)
  • $ssl_cipher: 返回使用的SSL/TLS加密套件名称
  • $ssl_ciphers: 返回客户端支持的密码列表(1.11.7)
  • $ssl_client_escaped_cert: 以PEM格式(urlencoded)返回已建立SSL连接的客户端证书(1.13.5);
  • $ssl_client_cert: 以PEM格式返回已建立的SSL连接的客户端证书,不推荐使用,建议使用 ssl_client_escaped_cert 变量。
  • $ssl_client_raw_cert: 以PEM格式返回已建立SSL连接的客户端证书;
  • $ssl_client_fingerprint: 返回已建立SSL连接的客户端证书的SHA1指纹(1.7.1);
  • $ssl_client_i_dn: 根据RFC 2253(1.11.6)返回已建立SSL连接的客户端证书的“issuer DN”字符串;
  • $ssl_client_s_dn: 根据RFC 2253(1.11.6)返回已建立SSL连接的客户端证书的“subject DN”字符串;
  • $ssl_client_serial: 返回已建立SSL连接的客户端证书的序列号;
  • $ssl_client_sigalg: 返回已建立SSL连接的客户端证书的签名算法(1.29.3), 仅当使用OpenSSL 3.5或更高版本时才支持该变量。
  • $ssl_client_v_start 和 $ssl_client_v_end: 返回已建立SSL连接的客户端证书的开始和结束时间;
  • ssl_client_v_remain: 返回已建立SSL连接的客户端证书剩余有效期(1.7.1);
  • $ssl_client_verify: 返回客户端证书验证结果,可能的值有:SUCCESS、FAILED: 证书未发送(1.5.7)、FAILED: 证书被拒绝(1.5.7)、NONE 或 FAILED: 未知原因。
  • $ssl_curve: 返回用于SSL握手密钥交换过程的协商曲线(1.21.5)。
  • $ssl_curves: 返回客户端支持的曲线列表(1.11.7)
  • $ssl_early_data: 如果使用TLS 1.3早期数据且握手未完成,则返回“1”,否则返回“”(1.15.3).
  • $ssl_ech_outer_server_name: 如果接受TLS 1.3 ECH,则返回通过SNI请求的公共服务器名称,否则返回“”(1.29.4);
  • $ssl_ech_status: 返回TLS 1.3 ECH处理的结果:“FAQUE”、“EQUEND”、“GREASE”、“SUCCESS”或“NOT_TRIED”(1.29.4);
  • $ssl_session_id: 返回当前的SSL会话ID(1.13.0),注意其受到SSL会话缓存大小以及时间限制);
  • $ssl_session_reused: 如果SSL会话被重用,则返回“r”,或者“.”否则(1.5.11)。
  • $ssl_sigalg: 返回已建立SSL连接的服务器证书的签名算法(1.29.3)。

好了,接下来我们接入正题,来看看如何在 Nginx 中配置 客户端 与 Nginx 服务端双向认证。


示例演示

步骤 01.将上一篇《Nginx | 核心知识150讲,百万并发下性能优化之SSL证书签发与HTTPS加密传输实践笔记》文章中生成的 ca、server、client 证书和私钥文件拷贝到 Nginx 的 /usr/local/nginx/certs/ 目录下,如下所示:

cp /tmp/certs/ca.crt /tmp/certs/ca.key /usr/local/nginx/certs/

cp /tmp/certs/server.crt /tmp/certs/server.key /tmp/certs/server_encrypted.key /tmp/certs/ssl_password.txt /usr/local/nginx/certs/

cp /tmp/certs/client.crt /tmp/certs/client.key /usr/local/nginx/certs/

步骤 02.在 Nginx 配置文件中添加 SSL 相关指令,如下所示:

tee /usr/local/nginx/conf.d/ssl_client_server.conf <<'EOF'
server {
  listen 80;
# 监听 443 端口,启用 SSL 
  listen 443 ssl;
# 虚拟主机服务器名称
  server_name server.weiyigeek.top;
  charset utf-8;
  default_type text/plain;

# 开起 HTTP/2 支持
  http2 on;

# 日志文件
  access_log /var/log/nginx/server.log main;
  error_log /var/log/nginx/server.err.log debug;

# SSL 证书文件
  ssl_certificate /usr/local/nginx/certs/server.crt;
  ssl_certificate_key /usr/local/nginx/certs/server.key;

# 配置加密的 SSL 证书密钥文件(根据需求选择)
# ssl_certificate_key /usr/local/nginx/certs/server_encrypted.key;
# ssl_password_file /usr/local/nginx/certs/ssl_password.txt;

# 配置可信的 CA 证书文件
# ssl_trusted_certificate /usr/local/nginx/certs/ca.crt;

# 配置客户端证书验证
  ssl_client_certificate /usr/local/nginx/certs/ca.crt;
  ssl_verify_client on;

# 指定客户端证书到根证书的深度 
  ssl_verify_depth 2;

# 支持的 SSL/TLS 协议版本
  ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

# 支持的 SSL/TLS 加密套件
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE:ECDH:AES:HIGH:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:!NULL:!aNULL:!eNULL:!EXPORT:!PSK:!ADH:!DH:!DES:!MD5:!RC4;

# SSL 会话缓存
  ssl_session_cache shared:SSL:10m;
# SSL 会话超时时间
  ssl_session_timeout 10m;
# 优先使用服务器端支持的加密套件
  ssl_prefer_server_ciphers on;


# 强制使用 HTTPS 访问
  add_header Strict-Transport-Security "max-age=31536000;includeSubDomains;preload" always;

  location / {
    root /usr/local/nginx/html;
    index index.html;
  }

  location /certificate {
    return 200 '客户端证书验证结果:$ssl_client_verify\nssl_server_name: $ssl_server_name\nssl_protocol: $ssl_protocol\nssl_client_fingerprint: $ssl_client_fingerprint\nssl_cipher: $ssl_cipher\nssl_client_i_dn: $ssl_client_i_dn\nssl_client_s_dn: $ssl_client_s_dn\nssl_client_v_start: $ssl_client_v_start\nssl_client_v_end: $ssl_client_v_end\nssl_client_v_remain: $ssl_client_v_remain\nssl_session_id: $ssl_session_id\nssl_client_cert:\n $ssl_client_cert';
  }
}
EOF

步骤 03.配置完成后,重启 Nginx 服务,并硬解析站点域名指向服务器 IP 地址,使用浏览器访问 https://server.weiyigeek.top/ 测试 https 是否配置成功,以及有何效果?由于客户端未发送证书,所以会提示“ 400 Bad Request No required SSL certificate was sent” ,从而无法正常访问到业务系统,如下图所示:

nginx -s reload

# Linux
echo '10.20.172.214 server.weiyigeek.top' >> /etc/hosts

# Windows
# C:\Windows\System32\drivers\etc\hosts
10.20.172.214 server.weiyigeek.top
weiyigeek.top-No required SSL certificate was sent图

步骤 04.接下来根据 client.key 和 client.crt 生成 pkcs12 格式的证书密钥打包文件,下载到机器后再将客户端证书导入到 Windows 系统证书管理器中,在 Windows 系统中,双击 client.pfx 文件导入到当前用户>个人/或者自动选择即可,或者 Ctrl + R 输入 certmgr.msc 打开证书管理器,选择“导入”,然后选择 client.pfx 文件即可。

$ openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx 
Enter Export Password:
Verifying - Enter Export Password:
weiyigeek.top-导入客户端证书到windows系统图

步骤 05.导入完毕后,在浏览器中访问 https://server.weiyigeek.top/ 如下图所示,选择导入的客户端证书。

weiyigeek.top-浏览器中选择客户端证书图

步骤 06.最后再次刷新访问 https://server.weiyigeek.top/certificate 测试一下客户端证书是否可正常访问站点,如图可以看到客户端证书验证结果为 SUCCESS,以及 SSL 加密套件以及客户端证书信息。

图片.png
weiyigeek.top-验证客户端双向认证图

步骤 07.若需要使用类似于 Postman 或 Apifox 客户端工具访问,双向认证站点时,需要导入客户端证书密码或者p12格式证书,这里以 Apifox 客户端工具为例,如下所示:

weiyigeek.top-在Apifox 客户端工具中配置认证图

知识扩展:有时候生产环境中想获取到服务端的公钥信息,可以使用 openssl s_client 命令进行获取:

$ openssl s_client -connect server.weiyigeek.top:443 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >./server.crt
depth=0 C = CN, ST = Chongqing, L = Chongqing, O = WeiyiGeek, OU = Nginx Server, CN = server.weiyigeek.top
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = CN, ST = Chongqing, L = Chongqing, O = WeiyiGeek, OU = Nginx Server, CN = server.weiyigeek.top
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 C = CN, ST = Chongqing, L = Chongqing, O = WeiyiGeek, OU = Nginx Server, CN = server.weiyigeek.top
verify return:1
DONE

$ ls -alh server.crt
-rw-r--r-- 1 root root 1.5K Dec 16 11:33 server.crt

至此,Nginx 服务端与客户端双向认证配置完成,是不是很简单呀,你也赶快试试吧!

END

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,持续更新包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。


Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?

✅ 将获得作者最新工作学习实践文章以及网盘资源。

✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买)

✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。

✅ 将获得作者远程支持(在作者能力范围内且合规)。


获取:作者工作学习全栈笔记

作者整理了10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者微信或者回复【工作学习实践笔记】,当前价格¥299,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!


 知识推荐 往期文章


    若文章对你有帮助,请将它转发给更多的看友,若有疑问的小伙伴,可在评论区留言你想法哟 💬

    【声明】内容源于网络
    0
    0
    全栈工程师修炼指南
    记录全栈工程师学习之路修炼心得,分享工作实践、网络安全、运维、编程、大数据、云原生、物联网、人工智能以及书籍笔记、人生职场感悟等相关高质量文章。 花开堪折直须折,莫待无花空折枝。 Blog:【https://weiyigeek.top】
    内容 589
    粉丝 0
    全栈工程师修炼指南 记录全栈工程师学习之路修炼心得,分享工作实践、网络安全、运维、编程、大数据、云原生、物联网、人工智能以及书籍笔记、人生职场感悟等相关高质量文章。 花开堪折直须折,莫待无花空折枝。 Blog:【https://weiyigeek.top】
    总阅读31
    粉丝0
    内容589