$ssl_client_v_start等变量仅在双向TLS握手成功且客户端证书有效时可用,需配置ssl_client_certificate和ssl_verify_client,支持日志记录与Lua动态策略,但不提供吊销状态等扩展信息。

OpenResty 或 Nginx(启用 ngx_http_ssl_module 且配置了 client certificate verification)中,$ssl_client_v_start、$ssl_client_v_end 和 $ssl_client_s_dn 等变量可用于在请求处理阶段获取客户端证书的元信息。但需注意:这些变量仅在成功完成双向 TLS 握手、且客户端提供了有效可验证证书时才可用;若证书未提供、验证失败或被吊销,这些变量为空或不可靠。
确认变量可用前提与基础配置
要使用 $ssl_client_v_start 等变量,必须满足以下条件:
- Nginx/OpenResty 编译时启用了 SSL 模块,并配置了
ssl_client_certificate(CA 证书路径)和ssl_verify_client on | optional - 客户端实际发送了证书,且该证书能被指定 CA 链成功验证(签名、有效期、用途等基本校验通过)
- 变量名拼写准确:
$ssl_client_v_start(证书生效时间,UNIX 时间戳)、$ssl_client_v_end(证书过期时间,UNIX 时间戳)、$ssl_client_s_dn(主体 DN 字符串) - 不依赖 Lua 的纯 Nginx 场景下,这些变量只能用于日志记录、变量赋值或简单判断;如需计算剩余天数、触发告警等,需配合 Lua(如 OpenResty 的 ssl_certificate_by_lua*)或后端服务
在 access\_log 中记录证书有效期信息
最直接的审计方式是将证书时间戳写入访问日志,便于离线分析与监控:
log_format cert_audit '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_user_agent" "$ssl_client_s_dn" '
'$ssl_client_v_start $ssl_client_v_end '
'($ssl_client_v_end - $ssl_client_v_start) sec';
access_log /var/log/nginx/cert-audit.log cert_audit;
说明:
-
$ssl_client_v_start和$ssl_client_v_end输出为秒级 UNIX 时间戳(如1672531200),可后续用脚本转为可读日期 - 日志中同时记录 DN,方便按用户/设备维度关联分析
- 注意:若客户端未提供证书或验证失败,对应字段将为空字符串,日志中显示为
-(取决于 log_format 中的占位)
用 Lua 动态检查并拦截即将过期的证书
在 OpenResty 中,可在 ssl_certificate_by_lua_block 阶段(TLS 握手期间、证书验证后)读取变量并做实时策略控制:
ssl_certificate_by_lua_block {
local start = tonumber(ngx.var.ssl_client_v_start)
local expire = tonumber(ngx.var.ssl_client_v_end)
local now = ngx.time()
<pre class="brush:php;toolbar:false;">if not (start and expire and expire > start) then
ngx.exit(400) -- 证书时间异常,拒绝
end
local days_left = math.ceil((expire - now) / 86400)
if days_left < 30 then
ngx.log(ngx.WARN, "Client cert for ", ngx.var.ssl_client_s_dn,
" expires in ", days_left, " days")
-- 可选:写入审计队列、触发告警、或降级处理(如记录但不限制)
end}
关键点:
- 该阶段发生在证书链验证通过之后、HTTP 请求尚未生成之前,适合做轻量级策略干预
- 务必对变量做类型和范围校验(如
tonumber()+ 非空判断),避免因空值导致 Lua 错误中断握手 - 不建议在此阶段直接
ngx.exit(403)拒绝临近过期的证书(除非策略严格),更推荐记录+告警+通知用户更新
补充说明:变量局限性与替代方案
需要清醒认识这些内置变量的边界:
- 它们不提供证书序列号、OCSP 响应状态、CRL 检查结果,也无法得知是否被吊销——这些需额外集成 OCSP Stapling 或调用外部校验服务
-
$ssl_client_v_start/$ssl_client_v_end是证书自身声明的有效期,不代表当前系统时间可信;若服务器时间错误,会影响“是否已过期”的判断逻辑 - 如需高精度审计(如按小时粒度预警、批量导出待更新证书列表),建议将日志接入 ELK 或 Prometheus + Grafana,或由后端 API 统一解析证书 PEM 内容(用 OpenSSL 命令或 Lua 的 ssl 模块)


















