必须用 ssl_verify_client on,且 ssl_client_certificate 指向的 CA 证书文件必须与客户端证书由同一 CA 签发;on 强制校验签名与有效期,失败返回 400,而 optional 不验证等同于形同虚设。

必须用 ssl_verify_client on,且 ssl_client_certificate 指向的 CA 证书文件必须与客户端证书由同一 CA 签发——差一个换行或空格,验证就失败。
ssl_verify_client 的取值陷阱
这个指令只有三个合法值:on、off、optional(或 optional_no_ca)。生产环境绝不能用 optional,它会让 Nginx 接收客户端证书但不校验签名,等同于“形同虚设”。
-
on:强制要求客户端提供有效证书,且必须能被ssl_client_certificate中的 CA 链验证通过;握手失败直接返回400 Bad Request -
optional:客户端可选提交证书,Nginx 不做任何验证($ssl_client_verify永远是SUCCESS),仅用于调试 -
optional_no_ca:客户端可选提交证书,Nginx 解析但不校验签发者——常见于需要读取 CN 但暂不启用 PKI 的过渡场景
错误现象:curl -k --cert client.crt --key client.key https://api.example.com 返回 SSL certificate problem: unable to get local issuer certificate,往往不是客户端问题,而是 Nginx 的 ssl_client_certificate 文件缺失、路径错,或内容被编辑器悄悄加了 BOM/空格。
CA 证书文件必须是 PEM 格式且不含私钥
Nginx 只认 PEM 编码的 CA 证书(即以 -----BEGIN CERTIFICATE----- 开头、-----END CERTIFICATE----- 结尾的 Base64 文本),且严禁混入私钥、密钥块或多个证书拼接(除非你明确配置了中间 CA 链)。
- 用
openssl x509 -in ca.crt -text -noout能正常输出证书信息,说明格式正确 - 若报错
unable to load certificate,大概率是文件用了 DOS 换行(\r\n)、开头有不可见字符,或误把ca.key当成ca.crt配置进去了 - 不要用
cat server.crt ca.crt > bundle.crt这种方式生成“CA 文件”——ssl_client_certificate只需根 CA 或可信中间 CA,不需要服务端证书
客户端证书信息怎么传给后端
Nginx 默认只在校验层使用客户端证书,不会自动把证书内容转发给 upstream。如果后端需要识别身份,必须手动透传变量:
-
proxy_set_header X-Client-Verify $ssl_client_verify;—— 值为SUCCESS/FAILED/NONE -
proxy_set_header X-Client-DN $ssl_client_s_dn;—— 提取 Subject 字符串,如CN=app-b-prod,OU=api,O=BankB -
proxy_set_header X-Client-Cert $ssl_client_cert;—— 原始 PEM 内容(含换行和空格),体积大、易出错,建议改用 Base64 编码:proxy_set_header X-Client-Cert-B64 $ssl_client_cert;(需确认 Nginx 版本 ≥ 1.19.0 支持该变量)
注意:$ssl_client_s_dn 是经过 Nginx 解析后的标准化字符串,比直接解析 PEM 更可靠;但它的字段顺序依赖 OpenSSL 版本,不要硬编码切分逻辑,应让后端用标准 ASN.1 库解析。
CRL 吊销检查不是默认开启的
Nginx 默认只校验证书签名和有效期,对已吊销证书完全无感。要启用 CRL 检查,必须显式配置:
- 先生成 CRL 文件:
openssl ca -gencrl -out crl.pem -config openssl.cnf - 在 server 块中添加:
ssl_crl /etc/nginx/ssl/crl.pem; - 确保 CRL 文件权限为 644,且 Nginx worker 进程可读
- CRL 文件过期后,Nginx 会拒绝所有客户端连接(日志报
error SSL_do_handshake() failed),必须定期更新并 reload 配置
真正容易被忽略的是:CRL 文件本身没有自动刷新机制,运维必须建立定时任务 + 文件校验 + reload 触发流程,否则吊销即失效。


















