服务器SSL证书审计日志的核心目标是记录谁、何时、用什么证书访问及验证结果;需配置ssl_verify_client on/optional和ssl_client_certificate,定义含$ssl_client_verify、$ssl_client_s_dn、$ssl_client_i_dn等字段的log_format,并在location中启用access_log实现精准审计。
服务器 SSL 证书审计日志的核心目标是:记录谁、何时、用什么证书访问了服务,以及证书验证是否成功。它不是单纯记录“用了 HTTPS”,而是聚焦在 TLS 握手环节的证书行为——尤其是双向认证(mTLS)场景下的客户端身份与验证结果。
启用并配置客户端证书验证
这是所有审计日志的前提。Nginx 中必须主动开启客户端证书校验,否则 $ssl_client_s_dn 和 $ssl_client_verify 这类变量始终为空。
- 在 server 块中设置 ssl_verify_client on(强制认证)或 ssl_verify_client optional(调试推荐,能捕获“未提供证书”的情形)
- 指定受信任的 CA 证书链:ssl_client_certificate /path/to/trusted-ca-bundle.pem
- 确保该 PEM 文件包含完整的根和中间证书,且权限为 644,Nginx 进程可读
定义结构化日志格式
仅记录 IP 或时间远远不够。审计需要上下文,所以 log_format 必须组合多个关键变量:
-
$ssl_client_verify:直接反映验证状态(SUCCESS / FAILED:reason / NONE)
-
$ssl_client_s_dn:客户端证书主题名,如 CN=user1,OU=API,O=Corp;需用双引号包裹,避免日志解析错乱
-
$ssl_client_i_dn:签发者 DN,用于追溯证书由哪个 CA 签发
- 补充 $ssl_protocol 和 $ssl_cipher:辅助判断是否因协议不兼容导致握手失败(虽非 verify 失败主因,但属排查链一环)
示例(放在 http 块中):
log_format ssl_audit '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_user_agent" ssl_verify="$ssl_client_verify" subject="$ssl_client_s_dn" issuer="$ssl_client_i_dn" proto="$ssl_protocol" cipher="$ssl_cipher"';启用日志并限定作用范围
把日志格式应用到具体位置,避免全站日志膨胀:
- 若只审计 API 接口,在对应 location 块中写:access_log /var/log/nginx/api-mtls.log ssl_audit;
- 确保日志路径存在、Nginx 用户有写入权限(如 chown www-data:www-data /var/log/nginx/)
- 建议同时开启 error_log warn 级别,例如:error_log /var/log/nginx/error.log warn;,部分 verify 失败细节(如证书过期)会出现在 error 日志里
后续分析与使用要点
日志写出来只是第一步,真正发挥审计价值要靠后续处理:
- DN 字符串含逗号和空格,解析时务必按双引号分隔字段(如 awk -F'"' '{print $6}'),再提取 CN 或 UID
- 注意:CN 不唯一,生产环境应要求证书包含 UID、email 或 serialNumber 等唯一标识,并通过 $ssl_client_cert 变量配合 OpenSSL 解析提取(较复杂,但必要)
- 定期检查日志中 FAILED 出现频率和原因,比如 “FAILED:certificate has expired” 表明需更新客户端证书,“FAILED:unable to get local issuer certificate” 则说明 CA 配置不全