要让nginx强制校验客户端证书有效性,必须在同一个server块内同时配置四要素:listen 443 ssl、ssl_certificate与ssl_certificate_key、ssl_client_certificate指向可信ca证书、ssl_verify_client on;还需根据证书链深度设置ssl_verify_depth,并通过proxy_set_header透传验证结果与证书信息。

要让 Nginx 强制校验客户端证书有效性,关键不是单独写 ssl_verify_client on,而是把它作为整套双向 TLS(mTLS)配置中的一环——必须四要素齐备、位置正确、CA 证书可信,缺一不可。
必须同时配置的四个核心指令
这四项必须全部出现在同一个 server 块内,顺序无关,但缺一就会导致校验不生效或直接报错:
-
启用 HTTPS 监听:用
listen 443 ssl;,否则 TLS 层根本不会启动 -
服务端身份凭证:
ssl_certificate和ssl_certificate_key指向 Nginx 自己的证书与私钥(用于向客户端证明自身) -
客户端信任锚点:
ssl_client_certificate /path/to/ca.crt必须是签发客户端证书的 CA 公钥(PEM 格式),且需含CA:TRUE;不能是客户端证书、服务端证书或私钥 -
强制验证开关:
ssl_verify_client on—— 设为on才会在 TLS 握手阶段就拒绝无证书或验证失败的连接(返回 400)
别忽略 ssl\_verify\_depth 的实际影响
若客户端证书由中间 CA 签发(例如:根 CA → 中间 CA → 客户端证书),默认 ssl_verify_depth 1 只能验证到中间 CA,无法上溯到根,结果就是 $ssl_client_verify 显示 FAILED:unable to get issuer certificate。此时应显式设为:
-
ssl_verify_depth 2(根 + 中间两级) - 或
ssl_verify_depth 3(适用于多级中间链)
用 openssl verify -CAfile ca.crt client.crt 验证本地证书链是否完整,再同步到 Nginx 配置。
验证通过后,如何把证书信息传给后端
Nginx 不会自动转发证书内容,需手动透传关键变量。在对应 location 块中添加:
-
proxy_set_header X-Client-Verify $ssl_client_verify;—— 后端可据此判断是否通过 mTLS -
proxy_set_header X-Client-DN $ssl_client_s_dn;—— 提取 CN、OU 等字段做用户识别 -
proxy_set_header X-Client-Cert $ssl_client_cert;—— Base64 编码的完整证书,供后端二次验签或存档
注意:$ssl_client_cert 在 ssl_verify_client on 下仅对验证成功的请求可用;若设为 optional,未提供证书时该变量为空。
路径级灵活控制(非全站强制)
Nginx 不允许在 location 块里直接写 ssl_verify_client,但可通过“全局启用 + 路径拦截”实现精准管控:
- 在
server块保持ssl_verify_client on,确保所有 HTTPS 请求都经历证书握手 - 在敏感路径(如
/admin/或/api/secure/)中加判断:
if ($ssl_client_verify != "SUCCESS") { return 403; }
这个 if 是安全的(仅用于条件返回,非重写),Nginx 官方明确支持。非敏感路径(如 /public/)则跳过该判断,保持兼容性。











