$ssl_client_fingerprint 在客户端发送证书且TLS握手成功时有值,为40字符SHA-1指纹;Nginx≥1.7.1支持,不依赖验证结果,仅用于日志标记与审计,需配合$ssl_client_verify等字段使用。

ssl_client_fingerprint 是 Nginx SSL 模块提供的一个只读变量,用于获取已成功建立 TLS 连接的客户端证书的 SHA-1 指纹(十六进制字符串,40 字符)。它不依赖双向认证是否通过验证,只要客户端在 TLS 握手阶段发送了证书且连接建立完成,该变量就有值。
这个指纹是客户端证书内容的唯一摘要,可用于识别、去重、审计或关联会话,比直接记录整个 $ssl_client_s_dn 更紧凑、更隐私友好,也避免了 DN 字段解析不稳定的问题。
什么时候 ssl_client_fingerprint 有值?
✅ 客户端发送了证书(无论是否启用
ssl_verify_client)✅ TLS 握手成功完成(即连接已建立)
✅ Nginx 版本 ≥ 1.7.1(官方自该版本起支持)
❌ 客户端未发送证书(如单向 HTTPS 场景)
❌ TLS 握手失败(如协议不匹配、证书格式错误、SNI 不匹配等),此时变量为空字符串
❌ 启用了
ssl_verify_client optional_no_ca但客户端根本没送证书,变量也为 ""
注意:即使
ssl_client_verify failed,只要证书被接收且握手完成,$ssl_client_fingerprint仍有效——这对分析“谁送了无效证书”非常关键。
如何在 access_log 中安全记录指纹?
推荐在 log_format 中定义含指纹的日志格式,并配合 map 做空值兜底:
map $ssl_client_fingerprint $fprint {
"" "-"; # 空指纹转为 "-"
default $ssl_client_fingerprint;
}
log_format mtls_full '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_user_agent" "$http_referer" '
'fingerprint="$fprint" '
'verify="$ssl_client_verify" '
'subject="$ssl_client_s_dn"';然后在 server 块中启用:
access_log /var/log/nginx/mtls_access.log mtls_full;
这样既保留指纹唯一性,又避免日志中出现空字段或乱码。
实际使用中的关键细节
- 指纹是 SHA-1 计算结果,不可逆,不泄露原始证书内容
- 同一客户端证书在不同请求中指纹始终一致,适合跨请求追踪
- 若客户端频繁更换证书(如自动轮换场景),指纹会变,需结合其他标识(如
$ssl_client_s_dn中的 CN/OU)做辅助关联 - 不要将指纹当作身份认证依据(它只是摘要,不是签名),仅用于日志标记与分析
- 在高并发场景下,该变量开销极低,无性能顾虑
和其他证书变量的配合建议
单独记录指纹价值有限,建议至少搭配以下字段之一:
-
$ssl_client_verify:区分SUCCESS/FAILED/NONE -
$ssl_client_s_dn:获取主题信息(注意正则提取需鲁棒,见知识库提示) -
$ssl_protocol+$ssl_cipher:排查是否因 TLS 版本或加密套件不兼容导致握手异常(虽不直接影响指纹生成,但影响其可用性) -
$ssl_server_name(SNI):确认客户端意图访问的服务名
这样一条日志就能支撑多数 mTLS 审计场景:是谁(指纹)、声称是谁(DN)、验证结果如何、用什么协议连的。
不复杂但容易忽略


















