Nginx原生不支持基于JA3等SSL指纹的流量分流,因其无法在不终止TLS前提下解析ClientHello字段;可行方案包括前置TLS解析代理或利用$ssl_protocol、$ssl_cipher等内置变量做粗粒度分流。

目前 Nginx 原生不支持直接解析 TLS 握手中的 JA3 指纹(它在 TCP 层之上、HTTP 层之下,属于 SSL/TLS 协议栈早期阶段),所以无法用 map 指令直接匹配 JA3 值。这是关键前提——不是配置写得不对,而是技术边界决定的。
为什么 map 不能处理 JA3?
Nginx 的 map 指令只能作用于已解析的 HTTP 变量,例如 $args、$http_user_agent、$host、$remote_addr 等。而 JA3 是客户端 ClientHello 消息中一系列字段(Cipher Suites、Extensions、Elliptic Curves 等)的 MD5 哈希值,它在 Nginx 接收到完整 HTTP 请求头之前就已完成协商。标准 Nginx(不含额外模块)根本接触不到这个数据。
- JA3 在 SSL handshake 阶段产生,早于 request line 和 headers 解析
- map 运行在 rewrite 阶段,依赖已解码的变量,无法访问原始 TLS 数据
- 官方 ngx_http_map_module 不提供 TLS 层钩子或 JA3 提取能力
可行的替代路径:需要外部模块或前置组件
若你确需基于 JA3 实现机器人拦截,必须引入能捕获并暴露 JA3 的扩展能力:
- OpenResty + lua-nginx-module + lua-resty-ja3:在 ssl_certificate_by_lua_block 阶段提取 JA3,存入 $lua_ja3 变量,再用 map 做后续映射(如标记风险等级)
- Nginx Plus R25+(商业版):通过 njs 模块配合 ssl_preread 指令,在 preread 阶段读取 ClientHello,但 JA3 计算仍需自定义 JS 逻辑,且不原生支持
- 前置 TLS 代理(如 Cloudflare Spectrum、Traefik + custom middleware、或自研 eBPF/DPDK 工具):在流量进入 Nginx 前完成 JA3 提取,并将结果以 HTTP header(如 X-JA3-Fingerprint)注入请求,Nginx 才能用 map $http_x_ja3_fingerprint … 安全判断
更务实的 Nginx 层机器人识别方案
放弃 JA3 并不意味着防御退化。生产中更稳定、可落地的组合策略如下:
-
用 map 标记可疑 User-Agent 组合:
map $http_user_agent $is_bot {
default 0;
~*(curl|wget|python-requests|go-http-client|masscan|nmap) 1;
~*HeadlessChrome 1;
} -
结合请求行为做多维 map 联动:
map $request_uri $is_suspicious_path { ~*^/(phpmyadmin|wp-login\.php|\.git/|\.env$) 1; default 0; }
map $http_referer $no_referer { "" 1; ~*google|bing|yahoo 0; default 1; } -
聚合判断后统一拦截:
set $block_flag 0;
if ($is_bot) { set $block_flag "${block_flag}1"; }
if ($is_suspicious_path) { set $block_flag "${block_flag}2"; }
if ($no_referer) { set $block_flag "${block_flag}3"; }
if ($block_flag ~ "1|2|3") { return 403; }
如果坚持要 JA3,部署建议
仅当安全要求极高、有专业团队支撑时考虑:
- 第一层:用 eBPF 或用户态 TLS 代理(如 sslsniff2)提取 JA3,打标后转发至 Nginx
- 第二层:Nginx 开启 proxy_set_header X-JA3 $http_x_ja3;再用 map $http_x_ja3 $ja3_risk { … } 做黑白名单映射
- 第三层:配合 limit_req_zone 基于 $ja3_risk 动态限速(如高风险指纹限 0.1r/s)
这种架构已超出纯 Nginx 配置范畴,本质是构建一个轻量级 TLS 指纹网关。











