找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1757

积分

0

好友

263

主题
发表于 4 天前 | 查看: 13| 回复: 0

在 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.0.1;
  • 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 中配置客户端与服务端双向认证,这是提升内部系统或API接口安全/渗透等级的重要手段。

步骤 01. 将之前生成的 CA 证书、服务器证书、客户端证书和私钥文件拷贝到 Nginx 的证书目录下。

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 服务。然后在客户端修改 hosts 文件,将域名指向服务器 IP,并通过浏览器访问 https://server.weiyigeek.top/ 进行测试。

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

由于此时客户端尚未提供证书,服务器会拒绝请求,浏览器通常会显示 “400 Bad Request No required SSL certificate was sent” 的错误。

步骤 04. 接下来,需要将客户端证书导入到访问设备的证书存储中。首先,将 client.keyclient.crt 合并生成为 PKCS12 格式(.pfx)的文件,方便在 Windows 等系统中导入。

openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx

生成过程中会提示设置导出密码。完成后,将 client.pfx 文件下载到客户端机器。在 Windows 系统中,可以双击该文件,或通过运行 certmgr.msc 打开证书管理器,将证书导入到“当前用户”的“个人”存储区。

步骤 05. 证书导入完毕后,再次使用浏览器访问 https://server.weiyigeek.top/。浏览器会检测到服务器要求客户端证书,并弹出窗口让用户选择已导入的证书。选择对应的客户端证书后继续。

步骤 06. 完成证书选择后,即可正常访问站点。为了验证双向认证成功并查看详细信息,可以访问 https://server.weiyigeek.top/certificate。该地址会返回一系列 SSL 变量信息,此时应能看到 $ssl_client_verify 变量的值为 SUCCESS,同时还能看到客户端证书的颁发者、主题、有效期等信息。

步骤 07. 若需要使用 API 测试工具(如 Postman 或 Apifox)访问配置了双向认证的接口,同样需要在工具中配置客户端证书。以 Apifox 为例,通常在请求的“证书”设置页,选择“P12”格式,然后上传 client.pfx 文件并输入生成时设置的密码即可。

知识扩展:获取服务端证书
有时候需要验证或获取服务端的公钥证书,可以使用 OpenSSL 命令连接并提取:

openssl s_client -connect server.weiyigeek.top:443 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./server.crt

执行该命令后,当前目录下会生成一个 server.crt 文件,其中包含了服务端的证书内容。

通过以上步骤,便完成了 Nginx 服务端与客户端之间 SSL 双向认证的配置与验证。这种配置极大地增强了通信链路的安全性,适用于对运维/DevOps安全要求极高的内部服务或金融、政务等敏感业务场景。




上一篇:WordPress项目导航菜单修改与Windows系统下Neo4j图数据库安装指南
下一篇:Linux运维必备:终端文件管理器ranger,告别命令行操作繁琐
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 21:10 , Processed in 0.207258 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表