错误信息
400 No required SSL certificate was sent
也可能输出为
- client sent no required SSL certificate while reading client request headers
页面标题是“400 No required SSL certificate was sent”;如果证书未通过验证,nginx 显示的则是“400 The SSL certificate error”。这条日志以 info 级别写入,因此在默认的 error_log 级别下看不到。
nginx — ssl_verify_client on, request without a client certificate
含义
nginx 配置了双向 TLS(ssl_verify_client on),而这个请求所用的 TLS 连接中,客户端没有出示证书。nginx 不会让握手失败,而是完成握手,然后对每个请求都返回这个 HTTP 400 页面,并以 info 级别记录“client sent no required SSL certificate”。问题要在客户端解决:客户端必须出示由 ssl_client_certificate 中的 CA 签发的证书。
原因
客户端没有发送证书
常见没有使用 --cert/--key 或相应库选项的 curl、脚本和 API 客户端;缺少证书机密的容器或 CI 作业。
浏览器中没有匹配的证书
常见浏览器只会提供由 nginx 公布的 CA(取自 ssl_client_certificate)签发的证书;如果证书来自其他 CA,或者根本没有导入证书,浏览器就什么也不发送。
nginx 前面的代理终止了 TLS
偶见前面的 CDN、负载均衡器或另一个 nginx 会自行建立不带客户端证书的 TLS 连接;这时必须在那一跳上配置双向 TLS(或者在边缘完成)。
修复方法
- 1.
出示客户端证书
把证书和密钥提供给客户端;对于浏览器以及 Windows/macOS 的密钥库,把它们打包成 PKCS#12,再导入该文件。
bash curl --cert client.pem --key client.key https://mtls.example.com/ # Browsers: import the client certificate with its key as PKCS#12 openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12 - 2.
代理到 mTLS 服务:配置上游证书
如果 nginx 本身就是 mTLS 服务的客户端,就由 proxy_ssl_certificate 和 proxy_ssl_certificate_key 在上游连接上提供证书。
text # nginx proxying to an mTLS upstream: present the client certificate on the upstream connection location / { proxy_pass https://mtls.example.com; proxy_ssl_certificate /etc/nginx/tls/client.pem; proxy_ssl_certificate_key /etc/nginx/tls/client.key; proxy_ssl_server_name on; } - 3.
只在需要的地方要求证书
使用 ssl_verify_client optional,再在每个 location 中检查 $ssl_client_verify,健康检查和公开路径无需证书也能访问。
text # Require the certificate only where needed ssl_verify_client optional; location /api/ { if ($ssl_client_verify != SUCCESS) { return 403; } }