How_to_align_with_TLS_fingerprinting

随着安全挑战不断增加,反机器人措施也在持续演进,合法爬虫有时也会被误伤。TLS 指纹识别便是其中一种隐蔽、尚未广为人知却相当有效的技术,可用于识别尝试连接服务器的设备。本文将说明它为何难以绕过,以及如何成功抓取所需数据。 

TLS 到底是什么?

要理解 TLS 指纹识别,先要了解 TLS 本身。 TLS 或 Transport Layer Security(其前身为 SSL – Secure Sockets Layer)是一种用于保护在线活动的协议,通常运行在 HTTP 连接之上。当你在 URL 旁看到锁形图标,或网站地址以 https 开头时,就表示已启用 TLS。如今,不使用 TLS 的网站已很少见。如果你尝试访问一个仅以“http”(没有“s”)开头的网站,浏览器通常会显示不安全连接警告,而不会直接打开网页。 

TLS 会在数据发送到目标服务器前将其加密,也就是转换成类似 9823h4brjhvbi 的随机字符串。因此,即使恶意行为者截获了信息,也无法读取或使用。不过,TLS 还必须确认数据发送给合法服务器,并确保该服务器能够解密这些数据。为此,TLS 会先建立连接:与目标服务器交换一系列消息,验证服务器身份、协商加密方式,并生成共享会话密钥,以便在通信期间保护和解密数据。 

这一过程称为 TLS 握手,以“ClientHello”消息开始。对于 TLS 指纹识别而言,这条消息尤为关键,因为服务器会据此识别连接的客户端。  

“ClientHello”消息包含什么

“ClientHello”消息不包含凭据等敏感数据,且以未加密形式传输,因此可以轻松捕获,并使用 Wireshark 等网络分析工具查看其内容。其中包含大量数据。 

  • TLS 版本 – 客户端支持的最高 TLS 版本。
  • Random – 客户端生成的随机数。
  • Session ID – 用于恢复会话,因此首次握手时为空。  
  • Cipher suites – 客户端支持的加密套件,按优先顺序列出。
  • Compression method – 如今几乎始终为 0。
  • Supported extensions – 客户端可能使用的附加功能,例如:
  • Server Name Indication (SNI) – 指定客户端请求的主机名。 
  • Application-Layer Protocol Negotiation (ALPN) protocol – 用于协商 TLS 连接上使用何种应用层协议的扩展。通常,Web 服务器会通过它协商 HTTP/1.1 或 HTTP/2。 
  • TLS libraries – 客户端使用的 TLS 库,不同客户端使用的库可能不同。
  • Signature algorithms – 用于验证服务器身份的受支持签名算法列表。
  • Elliptic curves – 指定加密通信中使用的椭圆曲线。 
  • Elliptic curve point formats – 指定点的编码方式。 

此外还有其他扩展。借助这些信息,网站可从“ClientHello”消息推断出许多与客户端有关的特征,例如软件栈、浏览器系列、设备类型和安全状态等。  

JA3 指纹识别方法

服务器收到“ClientHello”消息后,JA3 技术便可发挥作用。它由 Salesforce 维护,是最常用的指纹识别方案之一。JA3 关注消息中的五个关键部分:TLS 版本、cipher suites、扩展 ID、受支持组(elliptic curves)以及 elliptic curve point formats。每个部分都会转换为十进制格式,再用逗号和连字符拼接。由于原始指纹是一长串字符串,通常会使用 MD5 这一加密哈希函数生成固定的 128-bit 哈希值,便于比对。服务器随后会将结果与内部数据库中的已知指纹进行比较,有时也会使用公开数据库。 

其目的在于发现差异:该客户端看起来像普通 Web 浏览器,还是存在可疑之处?问题是,普通 Web 浏览器(如 Chrome)生成的哈希值往往与网页抓取编程库生成的哈希值不同,因为它们的 ClientHello 消息并不相同。JA3 算法只考虑少数变量,可能的指纹组合相对有限,因此较容易区分普通用户与抓取机器人。 

这说明 TLS 指纹识别能有效识别爬虫,也给依赖网页抓取的人带来不少难题。 

一些反网页抓取数据库会收录已知的 JA3 指纹。你可以计算自己的指纹,并检查它是否被列入白名单,以提高顺利访问的可能性。 

不过,JA3 指纹并非唯一可能暴露客户端为爬虫的因素。ClientHello 消息中各项取值的差异,也可能触发反机器人系统。例如:

  • 缺少 SNI 可能是危险信号,因为请求中通常应包含它。
  • 过时的 ALPN 请求可能被视为可疑活动的迹象,因为现代浏览器通常支持 HTTP/2。
  • Chrome 等浏览器支持的 elliptic curves 与编程脚本支持的不同,也可能引发怀疑。
  • Cipher Suites 列表按优先级排序,内容和顺序都应与常见 Web 浏览器保持一致。Extensions 也是如此。

让 TLS 指纹与浏览器保持一致的方法 

应对 TLS 指纹识别时,目标是让爬虫的指纹与常见 Web 浏览器一致。这并不容易,不过可以尝试以下几种方法,也可以结合使用。 

使用 PuppeteerPlaywright 或 Selenium 等成熟的浏览器自动化工具时,实际调用的是真实浏览器,因此可获得真实的指纹。这些工具不会改变 TLS 指纹,因此网站较难仅凭 TLS 判断发起连接的是普通浏览器还是无头浏览器。这就少了一个容易暴露的环节。

  • 轮换不同的浏览器和操作系统版本

如果你开展大规模网页抓取项目,这种方法有助于将连接分散到多个指纹上。 

  • 使用基于 LibCurl 的 HTTP 客户端 

你可以让这类客户端使用 curl-impersonate。它是 libcurl 的修改版本,可调整 TLS 指纹,使其看起来更像普通 Web 浏览器。支持 libcurl 的库包括 Typhoeus (Ruby)、Guzzle (PHP)、PyCurl (Python),以及 curl default 和 crul community libraries (R)。 

  • 调整 TLS 配置

如果你使用 Go 语言,可以借助相关库进行 TLS 伪装。Refraction Networking 的 utls、ja3transport 和 CycleTLS 等库都可用于此目的。

不过,使用 Java 或 Python 时,情况就没那么简单。对于 Java,可以使用 sslconfig.enabledCipherSuites 方法重新配置启用的 cipher suites 列表。对于 Python,最多只能通过 requests 和 httpx 配置 Cipher Suite 和 TLS 版本变量。调整这些变量或许有助于解决访问受阻问题,但指纹仍未必足够可信。 

  • 轮换其他要素 

如果所有流量都使用同一个 TLS 指纹,即便它看起来真实,也可能显得可疑。可以轮换其他可变要素,例如 cookies、user agent、headers 和 IP 地址。这会在一定程度上改变 ClientHello 消息,因此 JA3 指纹也会不同。 Multi-account browsers高质量代理 有助于实现这一点。 

结语

最后,需要注意的是,适配 TLS 指纹识别并不容易,因为不同网站可能会对 TLS 协议作细微调整,也各自拥有允许或拒绝访问的标准及数据库。要成功伪装 TLS 指纹,应针对每个网站分别分析,找出会触发其指纹识别机制的因素,以及它如何调整标准协议。此外,如今的网站会将 JA3 指纹等网络层信号与字体、屏幕分辨率等应用层信号结合使用。因此,仅靠 TLS 伪装还不够,你需要让爬虫的各项特征都尽量真实。同时也应定期检查,因为网站会频繁更新政策和检测方案,新的反机器人方法也会不断出现。只有同步调整,才能持续获得准确数据。 当然,你应始终遵守适用的规则,只抓取允许获取的数据,避免给目标网站造成过载,并使用可信工具,例如来源可靠的代理。 DataImpulse 可以在最后一点上提供帮助:点击 “Try now” 按钮,或通过 [email protected] 联系我们,如有任何问题。

Share article: