• 正文
  • 相关推荐
申请入驻 产业图谱

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

6小时前
243
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是 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_verifynssl_server_name: $ssl_server_namenssl_protocol: $ssl_protocolnssl_client_fingerprint: $ssl_client_fingerprintnssl_cipher: $ssl_ciphernssl_client_i_dn: $ssl_client_i_dnnssl_client_s_dn: $ssl_client_s_dnnssl_client_v_start: $ssl_client_v_startnssl_client_v_end: $ssl_client_v_endnssl_client_v_remain: $ssl_client_v_remainnssl_session_id: $ssl_session_idnssl_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:WindowsSystem32driversetchosts
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 加密套件以及客户端证书信息。

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 服务端与客户端双向认证配置完成,是不是很简单呀,你也赶快试试吧!

 

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

相关推荐

Baidu
map