nginx实现严格客户端证书吊销与链验证,必须在同一个server块中同时配置ssl_verify_client on、ssl_client_certificate(pem格式可信ca链)、ssl_crl(未过期pem格式crl)和ssl_verify_depth≥2;四者缺一不可,且crl须由链中某ca直接签发、权限正确、原子更新。

要在 Nginx 中实现严格的客户端证书吊销检查与完整证书链验证,关键不是堆砌指令,而是让 ssl_crl、ssl_client_certificate、ssl_verify_client 和 ssl_verify_depth 四者协同生效,且全部指向同一信任源。缺一不可,错一个就形同虚设。
必须同时启用的四项核心配置
这四个指令必须共存于同一个 server 块中,顺序无关,但缺一不可:
-
ssl_verify_client on:强制客户端提供证书并进入校验流程;设为
optional时ssl_crl完全不触发 -
ssl_client_certificate /path/to/trusted-ca-chain.pem:指定可信 CA 证书链(含根 CA 与中间 CA),必须是 PEM 格式、不含私钥、所有证书均需具备
CA:TRUE - ssl_crl /path/to/ca.crl.pem:指向由同一 CA 签发的 PEM 格式吊销列表,不能是 DER 或过期文件
- ssl_verify_depth 2:显式设为 2(或 3),确保能覆盖“客户端证书 → 中间 CA → 根 CA”三级链;默认值 1 会直接拒绝中间 CA 签发的证书
CRL 文件必须满足的硬性条件
Nginx 对 CRL 的要求非常严格,稍有偏差即静默失效:
- 格式必须为 PEM:若 CA 提供 DER 格式,用
openssl crl -inform DER -in ca.crl.der -outform PEM -out ca.crl.pem转换 - 必须未过期:运行
openssl crl -in ca.crl.pem -noout -nextupdate,当前时间须早于输出的Next Update时间 - 权限需正确:属主为 Nginx 工作用户(如
www-data),权限设为644,否则加载失败且日志只报 “Permission denied” - 签名必须可验证:CRL 必须由
ssl_client_certificate中某张证书直接签发;若客户端证书由中间 CA 签发,CRL 也应由该中间 CA 签署(或其上级)
证书链文件的正确构造方式
ssl_client_certificate 所指文件不是服务端证书链,而是专用于验证客户端证书的信任锚点:
- 合并根 CA 与中间 CA:用
cat root.crt intermediate.crt > trusted-ca-chain.pem,顺序不限,Nginx 会自动匹配路径 - 严禁混入客户端证书、服务端证书或私钥;也不要用编辑器添加空格、BOM 或 DOS 换行符
- 验证是否有效:运行
openssl x509 -in trusted-ca-chain.pem -text -noout,应能逐个输出每张证书信息 - 若中间 CA 缺失或
CA:TRUE属性错误,Nginx 日志通常只显示模糊的SSL_do_handshake() failed
更新与调试的关键实践
CRL 更新无需 reload Nginx,但操作必须原子化:
- 更新 CRL 时,先写入临时文件(如
ca.crl.pem.new),再用mv ca.crl.pem.new ca.crl.pem原子替换,新连接立即使用新版 - 调试时开启详细日志:
error_log /var/log/nginx/error.log debug;,重点关注 TLS handshake 阶段 - 本地模拟验证:用
openssl s_client -connect your.domain:443 -cert client.crt -key client.key -CAfile trusted-ca-chain.pem直接测试握手结果 - 若返回 HTTP 495/496,说明证书已提交但链路或吊销校验失败;返回 400 则大概率是客户端根本没发证书或格式错误











