nginx双向认证中客户端未发证书时,真实错误日志应为“peer did not return a certificate”,而非“unknown ca”;需检查ssl_client_certificate路径、ssl_verify_client配置,并用openssl s_client复现验证。

当 Nginx 启用 TLS 双向认证(mTLS)时,如果客户端未提供证书,通常会返回 400 Bad Request 或直接断连,错误日志中常见类似:
"SSL_do_handshake() failed (SSL: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca)"
但这个报错其实**不准确**——它常被误读为“CA 未知”,实际更可能是客户端根本没发证书(no certificate sent)。真正反映“客户端证书缺失”的关键线索在 Nginx 的 error log 中,需结合配置与日志交叉判断。
确认是否启用了 client_certificate 验证
双向认证必须显式开启证书验证。检查 Nginx 配置中是否有:
-
ssl_client_certificate /path/to/ca.crt;—— 指定受信任的 CA 证书(用于验证客户端证书签名) -
ssl_verify_client on | optional | optional_no_ca;——on表示强制要求客户端证书;optional表示允许无证书连接(但后续可通过$ssl_client_verify变量判断) -
ssl_verify_depth 2;(可选)—— 设置证书链验证深度
⚠️ 注意:ssl_verify_client optional_no_ca 不校验 CA,仅解码证书,此时即使客户端没送证书,也不会报错,但 $ssl_client_cert 为空 —— 这种模式下缺失证书不会触发 handshake 失败,而是静默通过。
查看 Nginx error log 中的真实握手失败原因
启用详细 SSL 日志(临时):
- 在
http或server块中添加:error_log /var/log/nginx/error.log debug; - 重启 Nginx(注意:debug 日志量大,仅调试时开启)
- 复现请求后,搜索日志中的关键词:
ssl3_read_client_certificate、no certificate sent、client did not return a certificate
典型有效线索示例:
2024/05/20 10:30:15 [info] 12345#12345: *6789 SSL_do_handshake() failed (SSL: error:140890C7:SSL routines:ssl3_get_client_certificate:peer did not return a certificate) while SSL handshaking
这个 peer did not return a certificate 才是客户端证书缺失的明确证据。
用 OpenSSL 手动模拟测试,隔离问题环节
绕过浏览器或业务客户端,用命令行确认行为:
- ✅ 正常带证书访问:
openssl s_client -connect example.com:443 -cert client.crt -key client.key -CAfile ca.crt - ❌ 模拟缺失证书(关键!):
openssl s_client -connect example.com:443 -CAfile ca.crt(不加-cert和-key)
观察输出末尾是否出现:Verify return code: 0 (ok)(说明握手完成但未发证书),同时 Nginx error log 应记录 peer did not return a certificate。若连接直接中断或报 unknown ca,说明问题可能出在 CA 文件路径、权限或格式(如 PEM 缺少 BEGIN/END 标记)。
检查客户端行为与中间设备干扰
不是所有客户端都默认发送证书。常见陷阱:
- 浏览器只在服务器明确请求证书时才弹窗提示选择(即 Nginx 发送 CertificateRequest 消息),而该行为依赖
ssl_verify_client on/optional且 CA 配置正确;若 CA 文件为空或路径错误,Nginx 不会发 CertificateRequest,客户端自然不发证 - cURL 默认不发送证书,必须显式指定:
curl --cert client.crt --key client.key https://example.com - 负载均衡器(如 ALB、SLB)、WAF 或代理若终止 TLS,则原始双向认证已丢失,需确保 TLS 终止点就是 Nginx 本身
可通过 Wireshark 或 tcpdump 抓包,过滤 tls.handshake.type == 11(CertificateRequest)确认 Nginx 是否发出证书请求。











