$ssl_client_escaped_cert 是 nginx 1.19.7+ 提供的只读变量,将客户端证书 pem 内容 url 编码后安全透传至后端,需配合 proxy_set_header 显式设置,前提为已启用 mtls 且 nginx 版本达标。

ssl_client_escaped_cert 是 Nginx 1.19.7+ 引入的变量,用于安全地将客户端证书的 PEM 内容以 URL 编码(percent-encoded)格式暴露给后端,避免因证书中含换行、空格、特殊字符导致 header 截断或解析错误。它不是配置指令,而是一个只读变量,需配合 proxy_set_header 或 fastcgi_param 显式透传。
✅ 正确启用的前提条件
- 已成功启用双向 TLS(mTLS),即:
ssl_verify_client on;-
ssl_client_certificate指向有效的 CA 证书(PEM 格式) -
ssl_certificate和ssl_certificate_key已正确配置
- 客户端在 TLS 握手时提供了由该 CA 签发的有效证书
- Nginx 版本 ≥ 1.19.7(可通过
nginx -v确认)
? 如何安全透传到后端
在 location 块中添加:
proxy_set_header X-Client-Cert-Escaped $ssl_client_escaped_cert;
⚠️ 不要用
$ssl_client_cert直接透传——它包含原始换行符和空格,HTTP header 中非法,多数后端会截断或报错。
其他常用配套 header(可选但推荐):
-
X-Client-Verify $ssl_client_verify→ 校验状态(SUCCESS/FAILED/NONE) -
X-Client-DN $ssl_client_s_dn→ 可识别的证书主题名(已自动转义,相对安全) -
X-Client-CN $ssl_client_s_dn_cn→ 仅提取 CN 字段(无换行,更轻量)
示例片段:
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 安全透传客户端证书(URL 编码格式)
proxy_set_header X-Client-Cert-Escaped $ssl_client_escaped_cert;
# 补充校验状态与身份标识
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-DN $ssl_client_s_dn;
}
? 后端如何安全解码使用(以常见语言为例)
| 语言 | 解码方式 |
|---|---|
| Python(Flask/Django) | urllib.parse.unquote(request.headers.get('X-Client-Cert-Escaped', '')) |
| Node.js(Express) | decodeURIComponent(req.get('X-Client-Cert-Escaped') || '') |
| Java(Spring Boot) | URLDecoder.decode(request.getHeader("X-Client-Cert-Escaped"), "UTF-8") |
| PHP | urldecode($_SERVER['HTTP_X_CLIENT_CERT_ESCAPED'] ?? '') |
✅ 解码后得到标准 PEM 字符串,含
-----BEGIN CERTIFICATE-----头尾,可直接用 OpenSSL 或语言原生 API 验证或解析。
❌ 常见错误与规避
误写成
ssl_client_escaped_cert on;
→ 这不是指令,是变量,不能单独配置;只支持$ssl_client_escaped_cert形式引用。未开启
ssl_verify_client或验证失败
→ 变量值为空字符串,后端解码后为"",需检查$ssl_client_verify是否为SUCCESS。Nginx 版本过低(
→ 该变量不存在,会静默为空;降级方案只能用$ssl_client_cert+ 后端预处理换行符(不推荐)。header 名称含下划线被代理/负载均衡器丢弃
→ 改用连字符命名,如X-Client-Cert-Escaped(更兼容),避免_。
✅ 验证是否生效
-
用 curl 携带客户端证书发起请求:
curl -k --cert client.crt --key client.key https://example.com/api/test
-
在后端打印接收到的
X-Client-Cert-Escaped值,确认其为类似:-----BEGIN%20CERTIFICATE-----%0AMIIC...%0A-----END%20CERTIFICATE-----
解码后应还原为合法 PEM,且能通过
openssl x509 -in - -text -noout验证。
不复杂但容易忽略。











