TLS指纹识别通过观察HTTPS连接是如何建立的——它提供哪些密码套件及其顺序、列出哪些扩展和椭圆曲线——在发送任何请求内容之前,识别打开HTTPS连接的软件。每个TLS库和每个浏览器版本向服务器打招呼的方式略有不同,即使之后的所有内容都被加密,这个问候对服务器来说也是明文可见的。JA3及其继任者JA4将问候转换为短哈希。反机器人系统将该哈希与声称的浏览器应该产生的哈希进行比较。这就是为什么一个自称是Chrome的Python脚本,通过一个完美的住宅IP连接,仍然会被捕获:IP说“柏林的家庭用户”;TLS握手说“脚本中的OpenSSL”。

指纹的来源:ClientHello

HTTPS连接以TLS握手开始。客户端发送的第一条消息是ClientHello。它是未加密的——必须如此,因为加密尚未协商——并且包含以下内容:

  • 客户端支持的TLS版本;
  • 它愿意使用的密码套件列表,按优先级顺序排列;
  • 一个扩展列表——SNI(主机名)、ALPN(应用协议,例如h2、http/1.1)、支持组(椭圆曲线)、签名算法、密钥共享、会话票据等——同样按特定顺序排列;
  • 它支持的椭圆曲线和点格式。

这些值都不是秘密,也不是针对每个站点选择的;它们内置于TLS库和使用它的应用程序中。Chrome 128发送特定的ClientHello;Firefox发送另一种;Python的ssl模块(OpenSSL)发送第三种;Go的crypto/tls发送第四种;curl发送第五种。服务器无论如何都会看到每个连接的ClientHello——它必须看到才能回答。记录和哈希它不需要任何成本。

JA3和JA4:将握手转化为签名

JA3

由Salesforce研究人员于2017年提出,JA3将ClientHello的五个字段——TLS版本、密码套件、扩展、椭圆曲线、椭圆曲线点格式——连接成逗号分隔的十进制列表,然后对字符串进行MD5哈希。结果是一个32字符的指纹,如cd08e31494f9531f560d64c695473da9。任何人都可以从数据包捕获中计算它,并且将JA3哈希映射到已知客户端的列表(“此哈希=Windows上的Chrome 120”,“此哈希=python-requests”)被广泛共享。

JA3有一个弱点,后来成为规避的功能:因为它按顺序哈希扩展列表,而Chrome(自版本110起)随机化每次连接的扩展顺序,因此单个Chrome安装会产生许多不同的JA3哈希。这是故意做的,以阻止服务器固化在一个指纹上——这使JA3在识别浏览器方面变得不那么有用。

JA4

JA4由FoxIO于2023年发布,旨在应对这一点。它在哈希之前对密码和扩展列表进行排序(因此Chrome的洗牌不再重要),保持某些字段可读,并纳入更多信号:连接是通过TCP还是QUIC、SNI类型、ALPN值、TLS版本以及密码和扩展的数量。JA4指纹看起来像t13d1516h2_8daaf6152771_e5627efa2ab1:第一个块表示“TCP上的TLS 1.3,15个密码,16个扩展,ALPN h2”,另外两个是排序密码列表和排序扩展列表加签名算法的截断哈希。JA4实际上是一个家族(用于TLS的JA4、用于HTTP头的JA4H、用于服务器端的JA4S、用于证书的JA4X等);当反机器人供应商今天说“TLS指纹”时,他们通常指的是JA4或类似构建的专有等价物。

为什么代理无法帮助

代理转发TLS握手;它不会重写它。使用HTTP代理时,客户端发送CONNECT host:443,代理打开TCP隧道,客户端的自己的ClientHello通过隧道原封不动地到达目的地。使用SOCKS5时,同样的事情发生在更底层。因此,目标服务器看到两个独立的事实:

  • 源IP——代理的,住宅且无瑕疵;
  • ClientHello——客户端的,准确说明是哪个库构建的。

然后,反机器人逻辑问一个简单的问题:TLS指纹是否与User-Agent匹配?User-Agent头声称“Windows上的Chrome 128”。JA4说“通过Python的OpenSSL 3.x”。真正的Chrome永远不会产生那个JA4。请求被标记——不是因为IP不好,而是因为故事内部不一致。这是“干净”的住宅代理在受保护网站上仍然获得CAPTCHA的最常见原因,也是为什么我们说代理回答来自哪里,而不是谁;参见代理做什么和不隐藏什么。

代理可以在一个方面起作用:一些提供商自己终止TLS(一个“中间人”代理,解密并重新加密,要求你安装其证书)。在这种情况下,目的地看到的是代理的ClientHello,而不是你的——这通常更糟,因为它是服务器端库,而不是浏览器。普通代理不会这样做。

每种客户端看起来像什么

客户端其TLS指纹表示什么与浏览器User-Agent一致?
真正的Chrome / Firefox / Safari该浏览器和版本,在该操作系统上是——它就是浏览器
Python requests、httpx、aiohttp由Python的ssl模块配置的OpenSSL否——无论头如何,都可识别为脚本
Node.js fetch / axiosNode的OpenSSL/BoringSSL构建否
Go net/httpGo自己的TLS栈;独特否
curl(默认构建)构建时的OpenSSL/LibreSSL否
通过Puppeteer/Playwright的无头Chrome真正的Chrome——正确的TLSTLS是;其他信号(自动化标志、缺少插件)可能仍然泄漏
“模拟”客户端(curl-impersonate、curl_cffi、tls-client)所选浏览器的ClientHello,逐字节复现是,如果你也将头与同一浏览器匹配

如何拥有一致的指纹

有三条诚实的路线,按成本递增。

  1. 使用真正的浏览器。使用Playwright或Puppeteer自动化Chrome或Firefox;TLS则真正是浏览器的。比原始HTTP更慢更重,但对于受保护的网站,这是基线。将每个浏览器上下文与自己的代理配对——参见Playwright、Puppeteer和Selenium中的代理。
  2. 使用模拟HTTP客户端。诸如curl_cffi(Python,基于curl-impersonate)和tls-client之类的库复现特定浏览器的ClientHello和HTTP/2设置,因此你获得爬虫速度与浏览器指纹。然后你必须保持所有其他头与同一浏览器版本一致——User-Agent、Accept-Language、sec-ch-ua客户端提示——否则你用一个矛盾换另一个。我们的Python代理指南展示了从requests切换到curl_cffi。
  3. 停止假装。如果目标提供官方API,请使用你的真实客户端身份。TLS指纹识别只有在指纹与声明矛盾时才是问题。

什么不起作用:在requests上设置Chrome User-Agent。它更改一个头,但保持握手不变——不匹配现在比以前更尖锐,因为带有OpenSSL指纹的普通python-requests UA至少是自洽的。

更大的图景:指纹堆叠

TLS是一层。现代反机器人供应商还指纹识别HTTP/2连接(SETTINGS帧值、窗口大小、头顺序和伪头顺序——有时称为Akamai指纹识别)、TCP/IP栈(窗口大小、TTL、选项;经典p0f),当然还有通过JavaScript的浏览器本身,HTTP客户端根本无法运行。每一层必须与其他层和IP讲述相同的故事。具有浏览器TLS指纹和浏览器HTTP/2设置但没有JavaScript执行的住宅IP,在期望JS挑战运行的网站上仍然是异常。这就是为什么“哪个代理避免检测?”的诚实答案是“没有一个单独能”——以及为什么我们的排名权衡提供商在IP之外做了什么;参见精英代理比较。

如何查看自己的指纹

几个公共页面回显它们为你的连接计算的JA3/JA4,以及它们认为属于哪个浏览器。从真正的浏览器加载一个,然后通过相同的代理用你的脚本获取它,并比较。如果两者不同,你就找到了你的脚本与浏览器处理方式不同的原因——并且没有代理更改会修复它。每当目标已知运行企业反机器人时,将此添加到如何测试代理中的检查中。

常见问题

什么是JA3?

来自TLS ClientHello的五个字段(版本、密码、扩展、曲线、点格式)的MD5哈希,用于识别客户端软件。它适用于脚本和库;一旦Chrome开始随机化扩展顺序,它就对Chrome变得不可靠。

什么是JA4?

JA3的继任者:它在哈希之前对列表进行排序,因此扩展洗牌不会改变它,保持部分指纹可读,并包括传输(TCP/QUIC)、ALPN和计数。它是当前大多数TLS指纹检测的基础。

住宅代理会改变我的TLS指纹吗?

不会。代理隧道传输你的握手不变;目的地看到代理的IP和你的ClientHello。只有客户端软件决定指纹。

我可以在Python中伪造浏览器的TLS指纹吗?

可以,使用模拟客户端,如curl_cffi,它复现所选浏览器的ClientHello和HTTP/2行为。你必须保持头与同一浏览器一致。普通的requests/httpx无法做到这一点。

TLS指纹识别与浏览器指纹识别相同吗?

不。TLS指纹识别读取加密连接的握手并识别客户端软件;浏览器指纹识别运行JavaScript并识别设备(画布、字体、GPU)。反机器人系统使用两者,加上IP信誉,并检查它们是否一致。

为什么同一个脚本在一个站点被阻止而在另一个站点不被阻止?

因为TLS指纹检查是企业反机器人产品的功能,而不是整个网络的功能。没有此类保护的站点从不查看握手;有此类保护的站点在每个请求上将其与User-Agent进行比较。