nginx透传客户端证书信息需先启用ssl_verify_client on并成功验证证书,再通过proxy_set_header传递x-ssl-client-cert、x-ssl-client-dn等头字段,后端须校验x-ssl-client-verify为success并结合指纹白名单使用。

Nginx 透传客户端证书信息,主要用于双向 TLS(mTLS)认证场景,即后端服务需要基于客户端证书做身份识别或权限校验。这和透传 IP 或协议不同,它依赖 Nginx 主动提取并安全转发证书元数据,前提是已启用并成功验证客户端证书。
必须先启用客户端证书验证
Nginx 不会自动读取或传递证书,除非明确开启验证:
location /api/ {
ssl_verify_client on; # 强制要求客户端提供证书
ssl_verify_depth 2; # 验证证书链深度(通常 1–2 足够)
ssl_client_certificate /path/to/ca-bundle.crt; # 根 CA 或中间 CA 证书
# 可选:拒绝未带证书的请求(on),或仅尝试验证(optional)
}
只有当 ssl_verify_client on 生效,且客户端成功提交并被验证通过时,$ssl_client_cert、$ssl_client_s_dn 等变量才非空。
正确透传证书相关头字段
在 location 块中(不能写在 http 全局块),使用 proxy_set_header 传递以下关键变量:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
-
X-SSL-Client-Cert:原始 PEM 格式证书(含换行符和空格) -
X-SSL-Client-DN:证书主题 DN(Distinguished Name),如/CN=alice/O=Org -
X-SSL-Client-Verify:验证结果,值为SUCCESS、FAILED或NONE -
X-SSL-Client-Fingerprint:证书 SHA-256 指纹(需 Nginx ≥ 1.19.0)
示例配置:
location /api/ {
proxy_pass https://backend;
# 仅在证书验证成功时才有意义
proxy_set_header X-SSL-Client-Cert $ssl_client_cert;
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Client-Fingerprint $ssl_client_fingerprint;
# 同时别忘了基础透传(Host、Proto、IP等)
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
⚠️ 注意:$ssl_client_cert 的值包含换行符(\n)和缩进空格,在 HTTP Header 中不合法。后端接收时需做预处理:
- 推荐做法:前端 Nginx 不直接透传 PEM,而是用
map+base64编码(需nginx-plus或自编译模块); - 更通用做法:后端收到
X-SSL-Client-Cert后,将\n替换为\r\n,再拼成标准 PEM(-----BEGIN CERTIFICATE-----\r\n...); - 实际生产中,多数系统优先信任
X-SSL-Client-DN+X-SSL-Client-Verify: SUCCESS,再结合X-SSL-Client-Fingerprint白名单校验。
后端如何安全使用这些头
- 不要仅靠
X-SSL-Client-DN做权限控制——DN 可被伪造(若中间 CA 不受控); - 必须检查
X-SSL-Client-Verify是否为SUCCESS,排除验证失败或未提供证书的情况; - 强烈建议比对
X-SSL-Client-Fingerprint与预注册指纹库,实现细粒度证书绑定; - 若用 Spring Boot,可通过
@RequestHeader("X-SSL-Client-DN") String dn获取,并在 Filter 中统一校验; - Node.js 或 Python 应用应主动解析 PEM 并验证签名链(避免只信 header)。
调试技巧
- 临时把
proxy_pass指向一个 echo 服务(如 Python 的http.server打印所有 headers); - 用 curl 携带证书测试:
curl -k --cert client.pem --key client.key https://your-domain/api/test
- 查看 Nginx error log:若出现
client SSL certificate verify error,说明 CA 配置或证书格式有问题; - 检查
$ssl_client_verify是否为SUCCESS—— 这是透传有效的前提。
不复杂但容易忽略:证书透传不是“开了就通”,它是一条完整链路——Nginx 验证 → 提取变量 → 安全编码 → 后端校验 → 业务授权。每一步都必须显式确认。










