必须在 Nginx 的 stream{} 层用 nginx-ssl-ja3 模块提取 JA3,通过 proxy_set_header 透传至 WAF,并在 WAF 控制台启用对应 TLS 指纹识别功能;HTTP 层 Lua 提取不可靠且不推荐。

要在 Nginx 代理层把客户端的 JA3 指纹透传给后端 WAF(如阿里云独享版、华为云 WAF),核心是:在 TLS 握手阶段提取 JA3,再通过自定义 HTTP Header 安全传递,最后由 WAF 解析并执行策略。这不是简单加个 proxy_set_header 就能生效,必须分三步协同——提取、封装、识别。
JA3 必须在 Stream 层提前提取
JA3 是 Client Hello 阶段生成的 TLS 指纹,HTTP 层(http{} 块)无法获取。必须用 stream{} 上下文配合扩展模块:
- 编译安装
nginx-ssl-ja3模块(适配 OpenSSL 3.x + Nginx 1.25+),启用后可直接使用变量$stream_ssl_ja3 - 在
stream块中配置ssl_preread on,确保 TLS 握手未解密前就完成指纹提取 - 不能依赖
$http_ssl_ja3(该变量需 HTTP 层解析,已错过 Client Hello 时机)
用 proxy_protocol 或自定义 Header 向 WAF 透传
WAF 通常部署在 Nginx 后方或旁路,需明确指定传输方式:
- 若 WAF 支持 PROXY 协议(如四层负载均衡模式),在
stream的 upstream 中开启proxy_protocol on,并在 WAF 侧启用 PROXY 解析 - 更通用的做法:在
http块的location中,用proxy_set_header X-Forwarded-Tls-Ja3 $stream_ssl_ja3透传(注意:该变量需由 stream 层提前注入,常见做法是 stream → http 转发时携带) - 避免使用含特殊字符(如空格、换行)的原始值;JA3 是标准 32 字符 hex,可直接透传,无需 base64 编码
WAF 控制台需主动启用并配置 JA3 规则
仅透传 Header 不够,WAF 必须知道该字段含义并启用匹配能力:
- 在 WAF 控制台开启“TLS 指纹标识”或类似功能(华为云称“TLS 指纹识别”,阿里云独享版支持自定义 header 提取)
- 填写透传 header 名称,例如
X-Forwarded-Tls-Ja3 - 在精准访问控制规则中添加条件:“TLS 指纹(JA3) 包含 cd08e31494f9531f560d64c695473da9”——这个值来自爬虫工具指纹库,不是随机生成
- 建议搭配 IP + JA3 联合画像:同一 IP 出现多个 JA3,或高频命中黑名单指纹,直接阻断
不推荐在 HTTP 层用 Lua 提取 JA3
OpenResty 的 lua-resty-ja3 虽可用,但存在明显缺陷:
- 必须等 TLS 握手完成、请求进入 HTTP 阶段才执行,此时 Client Hello 已被 Nginx 内部丢弃,JA3 实际不可靠
- 性能开销大,且与原生
$stream_ssl_ja3存在精度差异(如 SNI、ALPN 等字段处理逻辑不同) - 真实用户切换浏览器/插件会导致 JA3 变化,WAF 策略应设为“高危指纹立即拦截”,而非“非白名单即拒绝”


















