Nginx 通过 $ssl_client_s_dn 获取客户端证书DN字符串,需启用mTLS并完成验证;配合 map 和正则可提取CN等字段,透传至后端需注意编码与日志调试。

Nginx 可以通过 $ssl_client_s_dn 变量获取客户端证书的可分辨名称(Subject Distinguished Name),前提是已启用双向 TLS(mTLS)并成功完成客户端证书验证。这个变量是字符串格式,包含类似 CN=alice,OU=dev,O=example.com 的内容,需进一步解析才能提取具体字段(如 CN、OU、O 等)。
确保客户端证书验证已启用
仅配置 ssl_client_certificate 和 ssl_verify_client 不足以让 $ssl_client_s_dn 生效;必须实际完成证书校验流程:
-
ssl_client_certificate /path/to/ca-bundle.crt;—— 指定受信任的 CA 证书(用于验证客户端证书签名) -
ssl_verify_client on | optional | optional_no_ca;—— 推荐设为on强制验证;设为optional时,无证书请求仍继续,但变量为空 -
ssl_verify_depth 2;—— 根据客户端证书链深度合理设置(通常 1 或 2)
直接使用 $ssl_client_s_dn 传递身份信息
该变量在 SSL 握手完成后即可用,常用于透传给后端服务(如通过 HTTP Header):
-
proxy_set_header X-Client-DN $ssl_client_s_dn;—— 后端可通过该 header 获取完整 DN 字符串 -
fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;—— PHP-FPM 场景下注入 CGI 变量 - 注意:DN 中可能含逗号、等号、空格或特殊字符(如 UTF-8),若需 URL 安全传输,建议用
$ssl_client_s_dn_encoded(Nginx 1.19.4+ 支持)或自定义 map 编码
提取特定字段(如 CN)需借助 map 指令解析
Nginx 原生不提供 DN 字段切分函数,但可通过正则 + map 提取常用项。例如提取 CN:
map $ssl_client_s_dn $client_cn {
~*CN=([^,;]+) $1;
default "";
}然后在 location 中使用:
proxy_set_header X-Client-CN $client_cn;- 正则注意大小写(
~*表示忽略大小写),匹配到第一个CN=xxx即止;多个 CN(极少见)只取首个 - 类似可定义
$client_ou(~*OU=([^,;]+))、$client_o(~*O=([^,;]+))等 - 若 DN 含引号或转义(如
CN="Alice Doe"),正则需增强:~*CN=(?:"([^"]+)"|([^,;"\]+)),并合并捕获组逻辑
调试与常见问题
开发阶段建议开启日志确认变量值是否正确生成:
- 在 log_format 中加入
$ssl_client_s_dn或$client_cn,例如:log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$ssl_client_s_dn"'; - 若变量为空:检查证书是否被 CA 正确签名、客户端是否实际发送了证书、
ssl_verify_client是否为off或握手失败 - 若字段提取为空:用 log 输出原始
$ssl_client_s_dn,确认格式是否符合正则预期(如字段顺序、分隔符、大小写、是否存在引号) - 注意:
$ssl_client_s_dn仅在 HTTPS server block 及其子 location 中有效;HTTP 块中该变量始终为空


















