Nginx 启用严格 mTLS 的核心是 CA、客户端证书与配置三者严丝合缝:CA 文件须为无 BOM/空行/回车的纯 PEM 格式;客户端证书必须由该 CA 直接或按 ssl_verify_depth 指定层级签发;需通过 openssl verify 本地验证;并透传 $ssl_client_verify 和 $ssl_client_s_dn 至后端,同时补上 ssl_crl 吊销检查与权限隔离。

Nginx 启用严格的客户端 SSL 证书认证(即 mTLS),核心不是打开 ssl_verify_client on 就完事,而是整套 PKI 链路必须严丝合缝——CA、客户端证书、Nginx 配置三者必须精确对齐,任何一环格式或层级错位,都会直接返回 400 或 495 错误。
CA 文件必须是纯 PEM 格式,且不能有任何“隐形污染”
Nginx 对 ssl_client_certificate 指向的 CA 文件极其敏感:
- 只接受标准 PEM 编码(
-----BEGIN CERTIFICATE-----开头,-----END CERTIFICATE-----结尾) - 文件中不能有 BOM、空行、多余空格、Windows 回车符(
\r\n) - 若用文本编辑器“美化”过 ca.crt(比如 VS Code 自动加空行或转编码),Nginx 就会静默拒收,不报错但认证失败
客户端证书必须由该 CA 直接签发(或一级子 CA)
Nginx 默认只验证到 ssl_verify_depth 1:
- 如果你用 root CA 签发 client.crt,那
ssl_client_certificate就必须指向这个 root CA 的 PEM 文件 - 如果用了中间 CA(如 root → intermediate → client),则必须:
- 把 intermediate 的证书也放进
ssl_client_certificate所指文件(拼接顺序:intermediate 在前,root 在后) - 显式设置
ssl_verify_depth 2
- 把 intermediate 的证书也放进
- 不能只放 root CA 却让客户端用多级链证书,Nginx 不会自动向上追溯
证书生成与验证必须闭环,不能靠“差不多”
别手动拼接、别用自签再签、别跳过本地验证:
- 统一用同一份
ca.key+ca.crt签发所有 client.crt - 客户端私钥用
openssl genpkey -algorithm RSA -out client.key(不用genrsa,避免旧 ASN.1 格式兼容问题) - CSR 的 Subject 建议含唯一标识,例如
CN=api-app-prod,便于后续白名单控制 - 生成后立刻执行:
openssl verify -CAfile ca.crt client.crt
输出
client.crt: OK才算真正过关
把客户端身份安全透传给后端
Nginx 默认不转发证书信息,需显式设置:
-
proxy_set_header X-Client-Verify $ssl_client_verify;—— 值为SUCCESS或FAILED,后端可据此快速拦截 -
proxy_set_header X-Client-DN $ssl_client_s_dn;—— 如CN=api-app-prod,OU=API,O=MyBank,注意逗号和等号会被 URL 编码,后端要 decode 后解析 CN - 避免用
X-Client-Cert $ssl_client_cert(Base64 全证书),体积大、不必要,仅调试时临时启用
金融级必须补上的两个硬缺口
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
-
CRL 吊销检查默认关闭:即使证书已被 CA 吊销,只要没过期、签名有效,Nginx 仍放行。必须加:
ssl_crl /etc/nginx/ssl/ca.crl;
且确保 CRL 文件本身是 PEM 格式、定期更新、权限为 600
-
无权限隔离 = 形同虚设:若 Nginx 运行用户(如
nginx)能读取所有 client.key,攻击者一旦突破 Web 层,就可伪造任意合法客户端身份。应严格分离:- CA 文件和 CRL 由 root 管理,Nginx 用户只读
- 客户端私钥绝不存于 Nginx 可访问路径
不复杂但容易忽略

















