什么是TLS指纹?
TLS指纹是一种被动检测技术,根据客户如何启动加密连接来识别客户. 每次你的刮子机,浏览器,或HTTP库通过HTTPS连接到一个网站时,它都会发送一个TLS客户端Hello消息,其中包含密码套件,扩展,椭圆曲线,以及其他参数按特定顺序排列. 反机器人系统分析这种握手方式以确定连接客户端是否与其用户代理声称的匹配.
与 浏览器指纹,这需要JavaScript执行,TLS指纹在网络层工作——在任何页面内容交付之前. 这使得它成为最早期和最难侦测的信号之一 正如我们所覆盖的 关于反机器人系统如何检测代理的全面指南。 。 。
TLS 握手方式
在通过HTTPS交换任何HTTP数据之前,客户端和服务器进行TLS握手. 关键的第一个信息——客户端你好——包含所有用于指纹的反机器人系统:
- TLS 版本 : 客户端支持的最大TLS版本(如TLS 1.2,TLS 1.3).
- 密码套件 : 客户端愿意使用的加密算法的有序列表.
- 扩展名 : 其他能力如服务器名称标识(SNI),ALPN,签名算法,以及关键共享组.
- 椭圆曲线 : 支持键交换的曲线类型(如x25519,secp256r1).
- 压缩方法 : 通常在现代实施中是无效的,但它们的存在或不存在仍然是一种信号。
每个HTTP库,浏览器,以及编程语言运行时间都会产生一个独特的客户端Hello模式. Chrome, Firefox, Safari, Python's (英语). requests来,去 net/http,而Node.js各有可识别的签名.
JA3 指纹
JA3是部署最广泛的TLS指纹学方法. 由销售力量工程师开发,它从客户端Hello消息的五个字段创建了MD5散列:
| 外地 | 说明 | 示例数值 |
|---|---|---|
| TLS 版本 | 提供的协议版本 | 771(1.2立方磅)、772(1.3立方磅) |
| 密码套装 | 密码套件代码顺序列表 | 4865 -4866 -4867 -49195 -49199 ... .... |
| 扩展 | 扩展类型代码列表 | 0-23-65281-10-11-35-16-5. [永久失效連結] (中文(简体) ). |
| 椭圆曲线 | 支持的指定团体 | 29-23-24 (英语). |
| EC 点格式 | 支持的点格式类型 | 0 个 |
这5个值用逗号缩合,并用散列来产生32个特征的JA3指纹. 举例来说,Python的 requests 库生成一个与Chrome不同的JA3散列,即使两者设置了相同的用户代理字符串.
JA3 实践中的检测
# Example JA3 hash computation (conceptual)
# ClientHello fields → concatenated string → MD5 hash
# Python requests (urllib3/OpenSSL) — distinct JA3
# ja3: 771,4866-4867-4865-49196-49200-159-52393-52392-52394...,0-23-65281-10-11...
# ja3_hash: "773906b0efdefa24a7f2b8eb6985bf37"
# Chrome 120+ — different cipher order, different extensions
# ja3: 771,4865-4866-4867-49195-49199-49196-49200-52393-52392...,0-23-65281-10-11...
# ja3_hash: "cd08e31494f9531f560d64c695473da9"
# The hash reveals the client library, regardless of User-Agent
JA4——下一代
JA4,也来源于 Salesforce,通过制作更可读,更坚固的指纹来改进JA3. JA4不是一个不透明的MD5散列,而是建立了一个结构化的标识符,包含三个部分:
- JA4 a: (韩语). 协议类型 + TLS版本 + SNI存在 + 密码计数 + 扩展计数 + ALPN 第一值(如"t13d1517h2 8daaf6152771 b0da82ddd1658").
- JA4 b: (英语). 剪辑的密码套房
- JA4 c: 请检查url=值 (帮助). 排序的扩展散列(删除了SNI和ALPN以减少变异性).
JA4更难进行spoof,因为它包含了额外的信号,并采用了一种抵制简单的散列匹配的格式.
客户端常见的 TLS 指纹
| 客户端 | TLS 库 | 可识别特征 | 检测风险 |
|---|---|---|---|
| 颜色( 最新) | 无聊的SSL | 特定的密码顺序, GREASE 值, ECH 支持 | 低( 如果正确匹配) |
| 火花 | NSS (英语). | 不同的密码偏好, 授权的证书扩展 | 低( 如果正确匹配) |
| Python 请求 | OpenSSL (通过urlib3) Name | 缺少 GREASE 扩展、 OpenSSL 密码顺序 | 甚高楼 |
| 净点/http | 去密码/ tls | 唯一的密码顺序, 缺少许多扩展 | 甚高楼 |
| 节点.js(xios/got) | OpenSSL (通过节点) | 节点特定扩展命令, 缺少 GREASE | 高级 |
| 卷曲 | 变种(开放SSL/NSS/etc.) | 取决于建筑,但典型的非浏览器指纹 | 高级 |
TLS 指纹为何难于疏散
与其他检测方法相比,TLS指纹检测提出了独特的挑战:
- 网络层检测 : 它在任何HTTP内容交换之前运行,因此它不能被JavaScript注入或头部操纵所击败.
- 库级签名 : 指纹由编译为运行时间的 TLS 库决定,而不是由您的应用程序代码决定 。 更改用户代理字符串对TLS指纹产生零效应.
- 代理透明 : 标准HTTP/HTTPS代理(包括 住宅代办)将TLS的握手方式从客户端转发到服务器,因此源头看到了客户端真正的TLS指纹.
- 版本耦合 : 每个小版本的TLS库可以产生略微不同的指纹,使版本不匹配可以被察觉.
TLS 打印减灾战略
1. 使用浏览器- Grade TLS 库
最有效的方法是使用生成浏览器-同文客户端Hello消息的TLS库:
# Python: Use curl_cffi to mimic browser TLS fingerprints
# pip install curl_cffi
from curl_cffi import requests
# Impersonate Chrome's TLS fingerprint
response = requests.get(
"https://example.com",
impersonate="chrome",
proxies={
"http": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080",
"https": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
}
)
print(response.status_code)
2. 在 Go 中使用乌特
// Go: Use uTLS to mimic browser TLS fingerprints
// go get github.com/refraction-networking/utls
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"crypto/tls"
tls2 "github.com/refraction-networking/utls"
)
func main() {
proxyURL, _ := url.Parse("http://USERNAME:PASSWORD@gate.proxyhat.com:8080")
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
}
// uTLS allows you to specify a ClientHelloID that mimics
// specific browsers (Chrome, Firefox, Safari, etc.)
// This requires custom dial integration — see uTLS docs
_ = tls2.HelloChrome_Auto // Example: mimic Chrome
client := &http.Client{Transport: transport}
resp, err := client.Get("https://example.com")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body[:100]))
}
3. 使用自定义 TLS 的节点。
// Node.js: Use got-scraping for browser-like TLS
// npm install got-scraping
import { gotScraping } from 'got-scraping';
const response = await gotScraping({
url: 'https://example.com',
proxyUrl: 'http://USERNAME:PASSWORD@gate.proxyhat.com:8080',
headerGeneratorOptions: {
browsers: ['chrome'],
operatingSystems: ['windows'],
}
});
// got-scraping uses custom TLS settings to mimic browser fingerprints
console.log(response.statusCode);
4. 使用无头浏览器
无头浏览器(Puppeteer,Playwright)会因为使用真实的浏览器TLS堆栈而产生真实的浏览器TLS指纹. 这是最可靠的缓解措施,也是资源最密集的措施。 见我们的指南 刮刮而不受阻 为设置细节。
测试您的 TLS 指纹
在部署你的刮刮器之前, 对照检测服务验证其 TLS 指纹 :
# Check your JA3 fingerprint against a test service
# Using Python with curl_cffi
from curl_cffi import requests
response = requests.get(
"https://tls.peet.ws/api/all",
impersonate="chrome",
proxies={
"http": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080",
"https": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
}
)
data = response.json()
print(f"JA3 Hash: {data.get('tls', {}).get('ja3_hash', 'N/A')}")
print(f"JA4: {data.get('tls', {}).get('ja4', 'N/A')}")
print(f"HTTP Version: {data.get('http_version', 'N/A')}")
您的 TLS 指纹由您的 HTTP 客户端库决定, 而不是您的代理 。 从数据中心切换到住宅代理会改变你的IP声誉,但不会改变你的TLS签名. 必须处理这两层问题。
HTTP/2 指纹
在TLS之外,HTTP/2协议本身通过连接设置,头框顺序,以及优先级框架,揭示客户端身份. 反机器人系统结合了TLS和HTTP/2指纹,以达到更高的精度:
| HTTP/2 信号 | 它的启示 |
|---|---|
| 结构框架值 | 初始窗口大小, 最大并行流—— 客户端不同 |
| 视窗大小( U) | 流量控制递增值——每项实施独有 |
| 页眉帧顺序 | 修多头令 (:方法, :权威, :scheme, : path). |
| 优先事项框架 | 流的依赖性和重量——浏览器特有的模式 |
图书馆 curl_cffi 和 got-scraping 除了TLS指纹外,地址HTTP/2指纹.
将 TLS 缓解与代理旋转相结合
有效的反检测策略层 TLS 指纹匹配 高质量的代理旋转编号 :
- 匹配 TLS 到用户代理 : 如果你的用户代理声称Chrome,你的TLS指纹必须与Chrome匹配.
- 使用住宅代理 : 代理哈特的住宅代理 提供可补充浏览器级 TLS 签名的清洁IP.
- 连续旋转 : 每个会话应使用匹配的IP + TLS配置文件 + 用户代理组合.
- 避免混合库 : 不要用不同的TLS指纹重复使用同一个IP——这是一个强大的机器人信号.
- 部署前测试 : 使用测试端点校验您的指纹符合您声称的浏览器 。
关于特定语言的代理集成,请参见我们的指南: Py, (中文). 节点.js,以及 走开。 。 。
道德和法律考虑
TLS指纹仿真应负责使用. 合法使用的案例包括:
- 通过标准的HTTPS连接获取公开数据
- 安全研究和自身基础设施的渗透测试
- 确保您的自动测试精确模拟真实的浏览器行为
- 隐私研究,研究TLS指纹如何影响用户跟踪
始终遵守网站服务条款,费率限制和适用条例. 参见 代理哈特的文档 负责制定负责任的使用准则。






