绕过 Cloudflare DDos 防护(俗称“五秒盾”)
写爬虫的时候,有时会遇到源站套盾的情况,最近遇到一次,以此文记录。
本人暂时只能想到两种解决方式,不论哪种,都是需要一点 HTTP 基础在的。
TL;DR:
相较而言,绕盾是比较简单的,此法不行的话还有破盾做为保底方案。在这里,只讨论绕盾方案。
工具:
这次比较幸运,Shodan 可以很容易搜索到源站 IP,凭着自己的印象和 curl 工具,很快确定了哪个是正确的。如果 Shodan 没有记录,可以通过网络上其他方式来查找经过 Cloudflare CDN 套盾的源站 IP。本站虽然没套盾,但也是隐藏在 CDN 后面的,瑟瑟发抖 🙃 。
然而,源站做了 HTTPS 证书,是不能通过传统的方式 curl -H 'Host: somedomain' 'http://realip'
进行访问的。之前有过局域网内用 curl 做 HTTPS 接口测试的经验,很快找到保存的浏览器书签 How to test a HTTPS URL with a given IP address,经 curl 测试成功后,就可以将 curl https://DOMAIN.EXAMPLE --resolve 'DOMAIN.EXAMPLE:443:192.0.2.17'
迁移到代码上了。
由于 Laravel 9.x 内置的 HTTP 请求类支持自定义 Guzzle 选项,而 Guzzle 又支持添加 cURL 选项,这就非常方便了。关键代码如下:
<?php
class BaseModule
{
protected PendingRequest $httpClient;
protected const UA = '';
protected const BASE_URL = '';
public function __construct()
{
# 1. 通过指定 Guzzle 选项设置源站 IP
$this->httpClient = Http::withOptions([
'curl' => [
CURLOPT_RESOLVE => ['host:443:realip'],
],
'headers' => [
'User-Agent' => self::UA,
],
])->baseUrl(BASE_URL);
# 2. 通过传入自定义 Guzzle 客户端设置源站 IP
$this->httpClient = Http::baseUrl(BASE_URL)->setClient(new Client([
'curl' => [
CURLOPT_RESOLVE => ['host:443:realip'],
],
'headers' => [
'User-Agent' => self::UA,
],
]));
} // end __construct
} // end class
至此,绕盾成功 🎉 。
以子之矛,陷子之盾,何如
如果己方做为藏在 CDN 后面的源站点,该如何防止“绕盾”?只需要阻止非 CDN IP 的入站流量即可。