近期,笔者发现了一个神奇的网站。通过浏览器可以正常打开,但是通过curl命令或者代码访问时,却直接返回403错误。我猜测这一定是进行了用户代理(User-Agent)校验。于是,我在发送请求时附带了与浏览器相同的用户代理信息,但结果依然是403错误。
然而,这并没有使我灰心,我相信肯定还有其他请求头需要进行校验。于是,我打开浏览器的开发者工具,复制并添加了所有的请求头,确保我的请求与浏览器在HTTP协议层面完全一致。我以为这样一定不会失败,然而运行后依然遭遇到403错误。
服务端对客户端进行校验并没有什么黑科技,因为它们是通过TCP协议进行通信的。不可能出现这样的情况:浏览器发送的HTTP报文与我发送的完全相同的HTTP报文,但服务器能够识别出两者的差异。既然校验不是在HTTP层面进行的,那就只可能是在TLS层面进行校验。因此,我决定使用Wireshark来抓包,看看是否能找到在TLS握手过程中存在差异的地方。
众所周知,在TLS握手时,客户端会向服务端发送一个名为”client Hello”的报文,很有可能是根据这个报文来区分浏览器请求和非浏览器请求,因为在该报文中,客户端要告知服务端它所支持的加密套件、TLS版本等信息,而这些信息根据客户端的实现可能会有所差异。首先,我先抓取了一个正常浏览器请求的报文,然后与通过curl访问抓取的报文进行对比。
通过对比正常浏览器请求报文和通过curl访问抓取的报文,我发现两者之间确实存在很大的差异。经过逐一对比和排查后,我发现很有可能是因为curl的请求报文缺少”supported_versions”扩展信息导致了403错误。而浏览器在该扩展信息中的内容如下所示:
Extension: supported versions (len=5)
Type: supported versions (43)
Length: 5
Supported Versions length: 4
Supported Version: TLS 1.3 (0x0304)
Supported Version: TLS 1.2 (0x0303)
可以看出,浏览器支持TLSv1.2和TLSv1.3,并且在握手之后实际切换到了TLSv1.3。通过上述两组对比图可以明显看出,浏览器使用的是TLSv1.3,而curl使用的是TLSv1.2,这可能意味着只有使用TLSv1.3才能成功访问。
随后,我进行了验证,并经过反复验证发现,除了要指定TLSv1.3之外,还需要加上”Accept-Language”和”User-Agent”头,并且一定要使用HTTP/2协议。这三个条件缺一不可。然而,目前市面上流行的HTTP客户端基本上只支持HTTP/1.1,所以只能从基础库入手。
最终,我得出了一个结论:Cloudflare反爬虫维护了一组浏览器的TLS指纹,当收到客户端的”Client Hello”请求时,会检查这组指纹。如果无法匹配,就会拦截该请求,从而成功拦截掉大部分非浏览器发起的请求。这就是Cloudflare的基础验证机制。
那么,有没有什么更快更便捷的办法来绕开Cloudflare验证呢?答案是有的。
使用穿云API,您可以轻松地绕过Cloudflare的机器人验证,即使您需要发送10万个请求,也不必担心被识别为抓取者。
一个穿云API即可突破所有反Anti-bot机器人检查,轻松绕过Cloudflare、CAPTCHA验证,WAF,CC防护,并提供了HTTP API和Proxy,包括接口地址、请求参数、返回处理;以及设置Referer,浏览器UA和headless状态等各浏览器指纹设备特征。