绕过CloudFlare

如何绕过CloudFlare:突破反机器人保护系统

您需要抓取的大约 1/5 的网站使用 Cloudflare,这是一种核心反机器人保护系统,可以轻松阻止您。所以,应该用什么办法来绕过Cloudflare?我们花费了许多精力来弄清楚如何在 2023 年绕过 Cloudflare,并且编写了最完整的方法汇总。这些是您今天可以学到的一些技巧:

  • 方法 1:绕过 Cloudflare CDN。
  • 方法 2:绕过等候室并对进行逆向工程。
  • 方法 3:使用 Cloudflare 求解器。
  • 方法 4:强化无头浏览器。
  • 方法五:智能代理。
  • 方法 6:抓取 Google 缓存。
  • 方法 7:避免验证码。
  • 方法8:API绕过Cloudflare(最简单可靠)。

什么是 Cloudflare 机器人管理

Cloudflare 是一家网络性能和安全公司。在安全方面,他们为客户提供Web 应用程序防火墙 (WAF)。WAF 可以保护应用程序免受多种安全威胁,例如跨站点脚本 (XSS)、凭据填充和 DDoS 攻击。

他们的 WAF 中包含的核心系统之一是 Cloudflare 的 Bot Manager。作为机器人程序保护解决方案,其主要目标是在不影响真实用户的情况下减轻恶意机器人程序的攻击

Cloudflare 承认某些机器人的重要性。例如,任何网站都不想故意阻止 Google 或其他搜索引擎抓取其网页。为了解决这个问题,Cloudflare 维护了一个已知良好机器人的白名单

不幸的是,对于像你我这样的网络抓取爱好者来说,他们还假设所有未列入白名单的机器人流量都是恶意的。因此,无论您的意图如何,您的机器人很有可能会被拒绝访问受 Cloudflare 保护的网页

如果您之前尝试过抓取受 Cloudflare 保护的站点,您可能会遇到以下一些与Bot-manager 相关的错误

  • 错误 1020:访问被拒绝
  • 错误 1010:该网站的所有者已根据您浏览器的签名禁止您访问
  • 错误 1015:您的速率受到限制
  • 错误 1012:访问被拒绝

Cloudflare 如何检测机器人?

Cloudflare 使用的 bot 检测方法通常可以分为两类:被动和主动。被动机器人检测技术包括在后端执行的指纹检查,而主动检测技术则依赖于在客户端执行的检查。让我们一起深入研究每个类别的几个示例!

Cloudflare 被动机器人检测技术

以下是 Cloudflare 使用的一些被动机器人检测技术的非详尽列表:

检测僵尸网络

Cloudflare 维护已知与恶意机器人网络相关的设备、IP 地址和行为模式的目录。任何怀疑属于这些网络之一的设备要么被自动阻止,要么面临额外的客户端挑战来解决。

IP地址信誉

用户的 IP 地址信誉(也称为风险评分欺诈评分)基于地理位置、ISP 和信誉历史等因素。例如,属于数据中心或已知 VPN 提供商的 IP 的声誉将比住宅 IP 地址差。站点还可以选择限制从其服务区域之外的区域访问站点,因为来自实际客户的流量永远不应该来自那里。

HTTP 请求标头

Cloudflare 使用 HTTP 请求标头来确定您是否是机器人。如果您有非浏览器用户代理,例如python-requests/2.22.0,您的爬虫很容易被识别为机器人。如果 Cloudflare 发送的请求缺少标头,而这些标头本来会出现在浏览器中,那么它也可以阻止您的机器人。或者,如果您有基于用户代理的不匹配标头。例如,包括sec-ch-ua-full-version-list:Firefox 用户代理的标头。

TLS 指纹识别

这种技术使 Cloudflare 的反机器人能够识别用于向服务器发送请求的客户端。

虽然有多种 TLS 指纹识别方法(例如JA3JARMCYU),但每个实现都会为每个请求客户端生成一个静态指纹。TLS 指纹识别很有用,因为浏览器的 TLS 实现往往不同于其他发行版本、其他浏览器和基于请求的库。例如,Windows 上的 Chrome 浏览器(版本 104)具有与以下所有不同的指纹:

  • Windows 上的 Chrome 浏览器(版本 87)
  • 火狐浏览器
  • Android 设备上的 Chrome 浏览器
  • Python HTTP 请求库

TLS 指纹的构建发生在TLS 握手期间。Cloudflare 分析“客户端问候”消息中提供的字段,例如密码套件、扩展和椭圆曲线,以计算给定客户端的指纹哈希。

接下来,在预先收集的指纹数据库中查找该哈希以确定请求来自的客户端。假设客户端的散列匹配允许的指纹散列(即浏览器的指纹)。在这种情况下,Cloudflare 随后会将来自客户端请求的用户代理标头与与存储的指纹哈希关联的用户代理进行比较。

如果它们匹配,则安全系统假定请求来自标准浏览器。相反,客户端的 TLS 指纹与其宣传的用户代理之间的不匹配表明明显使用了自定义僵尸软件,导致请求被阻止。

HTTP/2 指纹识别

HTTP/2 规范是 HTTP 协议的第二个主要版本,于 2015 年 5 月 14 日作为RFC 7540发布。所有主要浏览器都支持该协议。

HTTP/2 的主要目标是通过引入标头字段压缩并允许在同一 TCP 连接上进行并发请求和响应来提高网站和 Web 应用程序的性能。为了实现这一点,HTTP/1.1 的基础被扩展了新的参数和值。这些新的内部结构是 HTTP/2 指纹的基础。

二进制框架层是 HTTP/2 的新增功能,是HTTP/2 指纹的核心焦点

如果您对 HTTP/2 指纹识别的更深入分析感兴趣,您应该阅读 Akamai 建议的 HTTP2 客户端指纹识别方法:Passive Fingerprinting of HTTP/2 Clients。但现在,这里有一个总结:

三个主要组件构成了 HTTP/2 指纹:

  • 框架: SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH, SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE, SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE, WINDOW_UPDATE
  • ** 流优先级信息:**StreamID:Exclusivity_Bit:Dependant_StreamID:Weight
  • 伪标头字段顺序::method:authority:scheme和标头的顺序:path

如果您好奇,可以单击此处测试实时 HTTP/2 指纹识别演示。

与 TLS 指纹一样,每个请求客户端都会有一个静态的 HTTP/2 指纹。为了确定请求的合法性,Cloudflare 始终验证请求中的指纹和用户代理对是否与存储在其数据库中的白名单相匹配。

HTTP/2 指纹和 TLS 指纹齐头并进。在 Cloudflare 使用的所有被动机器人检测技术中,这两种技术在基于请求的机器人中控制起来最具技术挑战性。然而,它们也是最重要的。所以,你要确保你做对了,否则就有被封锁的风险!

好吧!到目前为止,您应该对 Cloudflare 如何被动检测机器人程序有了很好的了解。但是,请记住:这只是故事的一半。现在,让我们来看看他们是如何积极主动的吧!

Cloudflare 主动机器人检测技术

当您访问受 Cloudflare 保护的网站时,许多检查会不断在客户端(即在您的本地浏览器中)运行,以确定您是否是机器人。以下是他们使用的一些方法的列表(同样,并非详尽无遗):

验证码

过去,验证码是检测机器人的首选方法。然而,众所周知,它们会损害最终用户的体验。Cloudflare 是否为用户提供验证码取决于几个因素,例如:

  • 站点配置。网站管理员可以选择始终、有时或从不启用验证码。
  • 风险级别。Cloudflare 可能会选择仅在流量可疑时提供验证码服务。例如,如果用户使用 Tor 客户端浏览网站,则可能会显示验证码,但如果用户运行标准网络浏览器(如 Google Chrome),则不会显示。对于这些情况,Cloudflare CAPTCHA 绕过是可能的,我们将在下面看到如何。

以前,Cloudflare 使用 reCAPTCHA 作为他们的主要验证码提供商。但是,自 2020 年以来,他们已经迁移到专门使用 hCaptcha。以下是出现在受 Cloudflare 保护的网站上的 hCaptcha 示例:

bypass_cloudflare

canvas指纹识别

Canvas 指纹允许系统识别 Web 客户端的设备类别。设备类是指用于访问网页的系统的浏览器、操作系统和图形硬件的组合。

Canvas 是一种HTML5 API,用于使用 JavaScript 在网页上绘制图形和动画。要构建画布指纹,网页会查询浏览器的画布 API 以呈现图像。然后对该图像进行哈希处理以生成指纹。

该技术依赖于将系统的图形渲染系统作为物理上不可克隆的功能。这听起来可能很复杂,所以让我解释一下。

画布指纹取决于计算系统的多个层,例如:

  • 硬件:显卡
  • 低级软件:GPU 驱动程序、操作系统(字体、抗锯齿/亚像素渲染算法)
  • 高级软件:Web 浏览器(图像处理引擎)

由于任何这些类别的变化都会产生唯一的指纹,因此该技术可以准确地区分设备类别。

我想澄清一下:画布指纹不包含足够的信息来充分跟踪和识别独特的个人或机器人。相反,它的主要目的是准确区分设备类别

在机器人检测的上下文中,这很有用,因为机器人往往会对其底层技术撒谎(通过其用户代理标头)。Cloudflare 拥有大量合法画布指纹 + 用户代理对数据集。使用机器学习,他们可以通过查找画布指纹与预期指纹之间的不匹配来检测设备属性欺骗(例如用户代理、操作系统或 GPU)。

Cloudflare 使用特定的画布指纹识别方法,即 Google 的Picasso Fingerprinting

如果您想查看画布指纹识别的实际效果,请查看Browserleak 的现场演示

事件跟踪

Cloudflare 将事件侦听器添加到网页。它们侦听用户操作,例如鼠标移动、鼠标单击或按键。大多数时候,真正的用户需要使用鼠标或键盘来浏览。如果 Cloudflare 发现一直没有使用鼠标或键盘,他们可以假设用户是机器人。

环境接口查询

这是一个非常广泛的类别。浏览器有数百个 Web API可用于机器人检测。我会尽力将它们分为4类:

  1. 特定于浏览器的 API。这些规范存在于一种浏览器中,但可能不存在于另一种浏览器中。例如,window.chrome是仅存在于 Chrome 浏览器中的属性。如果您发送给 Cloudflare 的数据表明您使用的是 Chrome 浏览器,但使用 Firefox 用户代理发送,他们就会知道有问题。
  2. 时间戳 API。Cloudflare 使用时间戳 API,例如Date.now()window.performance.timing.navigationStart来跟踪用户的速度指标。如果时间戳不像普通的人类浏览活动那样出现,用户将被阻止。一些示例包括:不人道地快速浏览或不匹配的时间戳(例如navigationStart加载页面之前的时间戳)。
  3. 自动浏览器检测。Cloudflare 在浏览器中查询仅存在于自动化 Web 浏览器环境中的属性。window.document.__selenium_unwrapped例如, or属性的存在分别window.callPhantom表示使用了SeleniumPhantomJS。出于显而易见的原因,如果检测到这种情况,您将被阻止。
  4. 沙盒检测。出于我们的目的,沙盒是指在非浏览器环境中模拟浏览器的尝试。Cloudflare 进行检查以阻止人们尝试使用模拟浏览器环境解决其挑战,例如在 NodeJS 中使用 JSDOM。例如,脚本可能会查找process object仅存在于 NodeJS 中的 。Function.prototype.toString.call(functionName)他们还可以通过在相关函数上使用来检测函数是否已被修改。

Cloudflare 僵尸程序保护的核心

与许多其他反机器人一样,Cloudflare 从上述所有方法收集数据作为传感器数据,并在服务器端验证它是否存在不一致。

哇,那是很多信息!您现在应该了解 Cloudflare 使用的机器人检测技术。

到目前为止,我们只讨论了高级概念,没有太多关于 Cloudflare 实际脚本的细节。不过别担心。我们将看看绕过 Cloudflare 的不同选项,从最直接的方法开始。

方法#1:通过调用源服务器绕过 Cloudflare CDN

Cloudflare 只能阻止通过其网络的请求,所以如果我们可以直接向源服务器发送请求不是很好吗?你和你想要的数据之间没有防御!

这并不总是可能的,但在可用时很有用。它首先查找托管内容的服务器的 IP 地址。获得原始 IP 后,您可以向不受 Cloudflare antibot 保护的服务器执行请求。

我们这里有两个步骤:获取源IP地址和执行请求

查找源IP地址

受 Cloudflare 保护的网站将隐藏其 DNS 记录……但可能并非无处不在:一些未受保护的子域、旧服务或邮件可能在同一域名下可用,但指向源服务器。

有几个站点可以为您提供有用的信息。例如,像ShodanCensys这样的数据库,或者像CloudFlairCloudPeler这样的工具,可能会展示它们的一些内部结构。并非所有目标都会出现在那里,许多目标不会有任何有用的条目,但有些可能会暴露其数据。

向源站服务器请求数据

你得到了原始IP地址,太棒了!可是现在……怎么办?您可以尝试将其粘贴到浏览器的 URL 栏中,但可能会失败。这是一种常见的服务器配置,只允许使用有效域名(比如 )example.com而不是 IP 地址进行连接。

但是使用域名去 DNS,对吧?所以我们需要避免这些。

您可以尝试像 cURL 这样的工具,它允许您向目标 IP 发送请求但强制主机。另一种选择是尝试强制您的主机文件(即/etc/hosts),因为该请求不会检查 DNS 并且会使用您在那里手动设置的 IP。

这一切听起来不错,但第一种方法在很多情况下都行不通。在下一节中,我们将通过分析其核心:Cloudflare 等候室,了解 Cloudflare 的反机器人如何将其防御技术付诸实践。

方法 #2:绕过 Cloudflare 等候室并对其挑战进行逆向工程

Checking if the site connection is secure

Checking your browser before accessing XXXXXXXX.com

如果您正在阅读本文,您将无法绕过 Cloudflare等候室并遇到以下情况:

bypass_cloudflare_challenge

也称为 Cloudflare JavaScript 挑战或 Cloudflare我受到攻击页面,这是 Cloudflare 的主要保护措施。如果想绕过Cloudflare,需要跳过Cloudflare waiting room。

什么是 Cloudflare 等候室?

当您在浏览器中访问受 Cloudflare 保护的站点时,您首先需要在 Cloudflare 等候室等待几秒钟。但是等候室有什么意义呢?在那段时间里,您的浏览器会解决挑战以证明您不是机器人。如果您被标记为机器人,您将收到“拒绝访问”错误。否则,您将自动重定向到实际网页。

绕过 Cloudflare 等候室需要多长时间?

您将被安排在候诊室等待几秒钟。确切时间取决于目标的安全级别以及您的爬虫在测试中的表现。对于受到高度保护的站点,此过程可能需要五到十秒钟。

一旦挑战被解决一次,您就可以自由浏览网站一段时间而无需再次等待。

我如何绕过 Cloudflare 的等候室

理想情况下,您可以通过解决 JavaScript 挑战并证明您是人类来绕过 Cloudflare 的等候室。

然而,一种可行的方法是分析 Cloudflare 的 JavaScript 挑战,以了解负责生成挑战和验证响应的算法。这样,您就可以对脚本进行逆向工程。

但为什么绕过 Cloudflare 的等候室很重要?

绕过 Cloudflare 等候室的目的是什么?

绕过 Cloudflare 等候室的目的是获得对现场数据的访问权限。对受 Cloudflare 保护的 URL 的每个请求都会遇到等候室,并且必须解决挑战才能重定向到实际网站。您的网络抓取工具必须经过相同的过程。

逆向工程 Cloudflare JavaScript 挑战

如果你想自己绕过任何反机器人系统,你首先需要对其进行逆向工程。创建 Cloudflare 旁路也不例外。

对于此示例,我们将对出现在AW LAB上的 Cloudflare 等候室页面进行逆向工程。请随时单击链接并继续操作!

第一步:查看网络日志

首先,在浏览器中打开开发人员工具并导航至“网络”选项卡。然后,我们将让它们保持打开状态并浏览 AW LAB 站点。

在我们从挑战页面重定向到实际站点后,我们会注意到以下关键请求(按时间顺序排列):

  • 首字母GETto https://en.aw-lab.com/,响应正文作为等候室的 HTML。HTML 包含<script>包含重要匿名函数的标签。此函数进行一些初始化并加载“初始挑战”脚本。
// The script from the waiting room HTML. 
(function () { 
    window._cf_chl_opt = { 
        cvId: '2', 
        cType: 'non-interactive', 
        cNounce: '12107', 
        cRay: '744da33dfa643ff2', 
        cHash: 'c9f67a0e7ada3f3', 
        /* ... */ 
    }; 
    var trkjs = document.createElement('img'); 
    /* ... */ 
    var cpo = document.createElement('script'); 
    cpo.src = '/cdn-cgi/challenge-platform/h/g/orchestrate/jsch/v1?ray=744da33dfa643ff2'; 
    window._cf_chl_opt.cOgUHash = /* ... */ 
    window._cf_chl_opt.cOgUQuery = /* ... */ 
    if (window.history && window.history.replaceState) { 
        /* ... */ 
    } 
    document.getElementsByTagName('head')[0].appendChild(cpo); 
})();

此脚本(连同更多后续脚本)会根据请求轮换,因此如果您在浏览器中跟随,它可能看起来略有不同。

  • AGET到“初始挑战”脚本:https://en.aw-lab.com/cdn-cgi/challenge-platform/h/g/orchestrate/jsch/v1?ray=<rayID>,其中来自上面<rayId>的值。window._cf_chl_opt.cRay它返回经过混淆处理的 JavaScript 脚本,您可以在此处查看。注意:此脚本会根据每个请求轮换更改。

bypass_cloudflare_initial_challenge

  • POST对 的请求,https://en.aw-lab.com/cdn-cgi/challenge-platform/h/g/flow/ov1/<parsedStringFromJS>/<rayID>/<cHash>其中<parsedStringFromJS>是在初始挑战脚本中定义的字符串,<cHash>是 的值window._cf_chl_opt.cHash。请求正文是格式为 URL 编码的有效负载:v_<rayID>=<initialChallengeSolution>. 此请求的响应正文似乎是一个长的 base64 编码字符串。

bypass_cloudflare_initial_challenge_solve

  • 的第二个POST请求https://en.aw-lab.com/cdn-cgi/challenge-platform/h/g/flow/ov1/<parsedStringFromJS>/<rayID>/<cHash>。负载遵循与先前请求相同的格式,并再次返回一个长的 base64 编码字符串。此请求负责发送第二个 Cloudflare 挑战的解决方案。

bypass_cloudflare_second_challenge_solve

  • 对 的最终POST请求https://en.aw-lab.com/,其中包含此格式的一些加密表单数据:
md: <string> 
r: <string> 
sh: <string> 
aw: <string> 

对此请求的响应为我们提供了目标网页的实际 HTML和一个cf_clearancecookie,使我们能够自由访问该站点而无需解决另一个问题

bypass_cloudflare_final_post

请求流没有给我们太多信息,特别是因为所有数据看起来都是加密的或随机文本流。因此,这排除了尝试通过黑盒逆向工程绕过 Cloudflare 的方法。

这可能会给您留下比开始时更多的问题。这些请求来自哪里?有效载荷中的数据代表什么?base64 响应主体的目的是什么?

好吧,没有比“初始挑战”脚本更好的搜索答案的地方了。到目前为止,我们一直避免深入查看 Cloudflare 的代码,但现在我们别无选择。请注意,这不是在公园散步!如果您已准备好迎接挑战,请加入我们。我们将从一些动态分析开始。

第 2 步:调试 Cloudflare Javascript 挑战脚本

对我们来说幸运的是,在撰写本文时,Cloudflare 未使用任何类型的反调试保护。打开浏览器的开发者工具,为所有请求设置XHR/fetch 断点

bypass_cloudflare_xhr_breakpoint

请务必清除您的 cookie,以便 Cloudflare 将您再次置于等候室。保持您的开发人员工具处于打开状态,导航至AW LAB

您会注意到,在“初始挑战”脚本加载后的几毫秒内,您的 XHR 断点被触发(在发送第一个 POST 请求之前)。

现在,您可以查看和访问当前范围内的所有变量和函数。但是,您无法从屏幕上显示的变量值中推断出太多信息,并且代码不可读。

仔细观察脚本,您会发现一个函数被调用了一千多次。在此示例中,这就是c函数(尽管它在您的脚本中可能具有不同的名称)。调用时,始终有一个字符串化的十六进制数字作为参数。让我们尝试在 DevTools 控制台中运行它:

bypass_cloudflare_string_concealing

哇!因此,Cloudflare 似乎使用了一种字符串隐藏混淆机制。通过运行该函数并将其调用替换为其返回值,我们可以将上面屏幕截图中的底部两行简化为:

// The simplified code 
(aG = aw["Cowze"](JSON["stringify"](o["_cf_chl_ctx"]))["replace"]("+", "%2b")), 
aE["send"](aB.FptpP(aB.RfgQh("v_" + o["_cf_chl_opt"]["cRay"], "="), aG));

使用在控制台中运行代码的相同技术,我们可以推断出变量o和分别aE代表windowXMLHttpRequest实例。我们还可以将括号表示法转换为点表示法以产生:

// The above code, even more simplified! 
(aG = aw.Cowze(JSON.stringify(window._cf_chl_ctx)).replace("+", "%2b")), 
    // aE = new XMLHttpRequest(), an XMLHttpRequest instance initialized earlier in the script 
    aE.send(aB.FptpP(aB.RfgQh("v_" + window._cf_chl_opt.cRay, "="), aG));

它并不完美,但代码对我们来说变得更容易阅读了。简化所有字符串隐藏函数调用将提高脚本的可读性。但是,手动执行此操作将花费很长时间。我们将在下一节中解决这个挑战,但现在让我们继续。

如果您在调试器中按下“继续直到下一个断点”按钮,您的浏览器将发送第一个发布请求。收到响应后,它会立即暂停在下一个断点:

bypass_cloudflare_breakpoint2

多么扭曲的情节!调试器暂停在一个完全不同的脚本中。这个新脚本就是我们所说的 Cloudflare 的“主要”或“第二”Javascript 挑战。但是如果你查看网络日志,没有GET请求这个特定的脚本!那么,它是从哪里来的呢?

仔细查看脚本,我们可以看到它是一个匿名函数。在我们的例子中,脚本名称是VM279. 根据StackOverflow 上的这个线程,这第二个脚本可能会在初始挑战脚本中使用eval或类似的方式进行评估。我们可以确认这一点,因为调用堆栈将 Cloudflare“初始挑战”脚本显示为发起者(参见:屏幕截图中的绿色框)!

如果我们点击发起者,我们可以在“初始挑战”脚本中看到这个脚本在哪里被评估:

bypass_cloudflare_newfunc

我们将使用相同的方法来评估c函数调用以撤消隐藏字符串并替换owindow,这为我们提供了以下信息:

// The line of code that initiates the second JavaScript challenge 
 
// Note: aE = new XMLHttpRequest(), an XMLHttpRequest instance initialized earlier in the script 
new window.Function(aB.pgNsC(ax, aE.responseText))();

看起来这个函数正在根据上responseText一个断点的 XMLHttpRequest 中包含的数据创建一个新函数。Cloudflare 可能使用一些密码将其解密为可执行脚本。

好的,我们取得了一些进展。然而,Cloudflare 脚本仍然不可读。即使通过手动调试,我们也无法弄清楚更多。如果你想创建 Cloudflare 绕过,我们需要能够完全理解它。为此,我们需要对其进行去混淆处理。

第 3 步:对 Cloudflare Javascript 挑战脚本进行去混淆处理

这不会是微不足道的。Cloudflare 在其代码中使用了很多混淆技术,在本文中涵盖所有这些技术是不切实际的。这是一个(非详尽的)示例列表:

  • 字符串隐藏。Cloudflare 删除了对字符串文字的所有引用。在上一节中,我们看到该c函数充当字符串隐藏器。
  • 控制流扁平化JUMPCloudflare通过使用无限循环和中央 switch 语句调度程序模拟类似汇编的指令来模糊程序的控制流这是来自 Cloudflare 脚本的示例:
// An example of control flow flattening from the Cloudflare script. 
function Y(ay, aD, aC, aB, aA, az) { 
    // The aB array holds a list of all the instructions. 
    aB = "1|6|11|0|15|9|3|10"["split"]("|"); 
 
    // This is the infinite loop 
    for (aC = 0; true; ) { 
        // The below switch statement is the "dispatcher" 
        // The value of the aB[aC] acts as an instruction pointer, determining which switch case to execute. 
        // After each switch statement finishes executing, the instruction pointer is incremented by one to retrieve the next instruction. 
 
        switch (aB[aC++]) { 
            case "0": 
                /* ... */ 
                continue; 
 
            case "1": 
                /* ... */ 
                continue; 
 
            case "3": 
                /* ... */ 
                continue; 
 
            case "6": 
                /* ... */ 
                continue; 
 
            case "9": 
                /* ... */ 
                continue; 
 
            case "10": 
                // Exit the function. This is the final switch case 
                return aD; 
 
            case "11": 
                /* ... */ 
                continue; 
 
            case "15": 
                /* ... */ 
                continue; 
        } 
 
        break; 
    } 
}
  • 代理功能。Cloudflare 将所有二进制操作(+-==/)替换为函数调用。这会降低代码的可读性,因为您需要不断查找额外函数的定义。这是一个例子:
// An example of proxy function usage 
 
az = {}; 
 
// '+' operation proxy function 
az.pNrrD = function (aB, aC) { 
    return aB + aC; 
}; 
// '-' operation proxy function 
az.aZawd = function (aB, aC) { 
    return aB - aC; 
}; 
// '===' operation proxy function 
az.fhjsC = function (aB, aC) { 
    return aB === aC; 
}; 
 
/* ... */ 
 
// Equivalent to ((1 + 3) - 4) === 0 
 
az.fhjsC(az.aZawd(az.pNrrD(1, 3), 4), 0);
  • 原子操作。特别是在主要/第二个挑战脚本中,Cloudflare 利用 javascript 的原子部分(一元表达式、数学运算和空数组)将简单的字符串或数字文字转换为长而复杂的表达式。这种技术很容易让人联想到JSFuck。例子:
 // Believe it or not, this is equivalent to: 
// a = 1.156310815361637 
a = 
    (!+[] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        [] + 
        (!+[] + !![] + !![] + !![]) + 
        -~~~[] + 
        (!+-[] + +-!![] + -[]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + 
        -~~~[]) / 
    +( 
        !+[] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        !![] + 
        [] + 
        -~~~[] + 
        (!+[] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![] + !![] + !![] + !![]) + 
        (!+[] + !![] + !![]) 
    );

使开发 Cloudflare 绕过变得非常重要的是其脚本的混淆和动态特性。每次进入 Cloudflare 等候室时,您都将面临新的挑战脚本。

如果您想创建自己的 Cloudflare 旁路,则需要一些高度专业化的技能。Cloudflare 的挑战脚本的混淆非常好,您不能将其放入通用反混淆器中并获得可读的输出。您需要创建一个自定义反混淆器,能够动态解析每个新的 Cloudflare 挑战脚本并将其转换为人类可读的代码。提示:尝试操纵脚本的抽象语法树

一旦您制作了一个有效的动态去混淆器,您将能够更好地理解 Cloudflare 的反机器人在您的浏览器上执行的所有检查以及如何复制挑战解决过程。

在下一步中,我们将从去混淆的 Cloudflare 脚本中分析一些主动机器人检测实现。让我们开始吧!

第四步:分析去混淆后的脚本

还记得那些神秘的有效载荷和 base64 编码的响应主体吗?好吧,现在我们可以了解它们是如何工作的了!

Cloudflare 的加密

回想一下这段代码片段,我们在其中确定响应文本用于评估主要/第二个挑战脚本:

// Note: aE = new XMLHttpRequest(), an XMLHttpRequest instance initialized earlier in the script 
new window.Function(aB.pgNsC(ax, aE.responseText))();

去混淆后的版本如下所示:

// Note: aE = new XMLHttpRequest(), an XMLHttpRequest instance initialized earlier in the script 
new window.Function(ax(aE.responseText))();

最后,ab.pgNsC只是该ax函数的代理包装器。反混淆ax函数如下所示:

ax = function (ay) { 
    var aF; 
    var aE = window._cf_chl_opt.cRay + "_" + 0; 
    aE = aE.replace(/./g, function (_, aH) { 
        32 ^= aE.charCodeAt(aH); 
    }); 
    ay = window.atob(ay); 
    var aD = []; 
    for ( 
        var aB = -1; 
        !isNaN((aF = ay.charCodeAt(++aB))); 
        aD.push(String.fromCharCode(((aF & 255) - 32 - (aB % 65535) + 65535) % 255)) 
    ) {} 
    return aD.join(""); 
};

你能猜出这个函数的作用吗?是解密函数!

Cloudflare 使用密码对主要/第二个挑战脚本进行加密。POST然后,在解决初始挑战的第一个请求之后,Cloudflare 返回加密的第二个挑战脚本。

为了真正执行挑战,它被解密成一个字符串,函数ax用作window._cf_chl_opt.cRay解密密钥。然后将该字符串传递给Function 构造函数以创建一个新函数并使用()!

我们之前还讨论了 Cloudflare 的主动机器人检测技术。现在,我们可以重新访问其中的一些以查看它们的实现!

验证码

在这里,我们可以看到 Cloudflare 如何加载 hCaptcha 实例:

o["_cf_chl_hload"] = function () { 
    o["_cf_chl_hloaded"] = true; 
}; 
 
q["push"](function (aD, aC, aA, az, ay) { 
    aA = false; 
    o["setTimeout"](aB, 3500); 
    aC = p["createElement"]("script"); 
    aD = "https://cloudflare.hcaptcha.com/1/api.js?endpoint=https%3A%2F%2Fcloudflare.hcaptcha.com&assethost=https%3A%2F%2Fcf-assets.hcaptcha.com&imghost=https%3A%2F%2Fcf-imgs.hcaptcha.com&"; 
    o["_cf_chl_hlep"] = "2"; 
    aC["src"] = aD + "render=explicit&recaptchacompat=off&onload=_cf_chl_hload"; 
    aC["onerror"] = aB; 
    p["getElementsByTagName"]("head")[0]["appendChild"](aC); 
 
    function aB(aI, aH, aG, aF, aE) { 
        if (o["_cf_chl_hloaded"]) { 
            return; 
        } 
 
        if (aA) { 
            return; 
        } 
        /* ... */ 
    } 
});
canvas指纹识别

在此代码段中,Cloudflare 正在创建一组画布指纹识别函数,以供稍后在脚本中使用:

S = [ 
    /* ... */ 
    function (a3, a4, a5, af, ae, ad, ac, ab, aa, a9, a8, a7, a6) { 
        a3.shadowBlur = 1 + O(L); 
        a3.shadowColor = R[O(R.length)]; 
        a3.beginPath(); 
        ad = a4.width / H; 
        ae = a4.height / H; 
        a8 = ad * a5 + O(ad); 
        a9 = O(ae); 
        a3.moveTo(a8 | 0, a9 | 0); 
        af = a4.width / 2 + O(a4.width); 
        aa = O(a4.height / 2); 
        ac = a4.width - a8; 
        ab = a4.height - a9; 
        a3.quadraticCurveTo(af | 0, aa | 0, ac | 0, ab | 0); 
        a3.stroke(); 
        return true; 
    }, 
    /* ... */ 
];
时间戳跟踪

Cloudflare 向浏览器查询时间戳的脚本中有很多地方。这是一个例子:

k = new Array(); 
pt = -1; 
 
/* ... */ 
if (window.performance.timing && window.performance.timing.navigationStart) { 
    ns = window.performance.timing.navigationStart; 
} 
for (var j = 0; j < 10; j++) { 
    k.push(Date.now() - ns - pt); 
}
事件跟踪

在这里,我们可以看到 CloudflareEventListener在网页中添加了 s 来跟踪鼠标移动、鼠标点击和按键操作。

function x(aE, aD, aC, aA, az, ay) { 
    aA = false; 
    aE = function (aF, aG, aH) { 
        p.addEventListener 
            ? p.addEventListener(aF, aG, aH) 
            : p.attachEvent("on" + aF, aG); 
    }; 
    aE("keydown", aB, aD); 
    aE("pointermove", aB, aD); 
    aE("pointerover", aB, aD); 
    aE("touchstart", aB, aD); 
    aE("mousemove", aB, aD); 
    aE("click", aB, aD); 
    function aB() { 
        /* .. */ 
    } 
}
自动浏览器检测

以下是 Cloudflare 为检测流行的自动浏览库的使用而必须进行的一些检查:

function _0x15ee4f(_0x4daef8) { 
    return { 
        /* .. */ 
        wb: !(!_0x4daef8.navigator || !_0x4daef8.navigator.webdriver), 
        wp: !(!_0x4daef8.callPhantom && !_0x4daef8._phantom), 
        wn: !!_0x4daef8.__nightmare, 
        ch: !!_0x4daef8.chrome, 
        ws: !!( 
            _0x4daef8.document.__selenium_unwrapped || 
            _0x4daef8.document.__webdriver_evaluate || 
            _0x4daef8.document.__driver_evaluate 
        ), 
        wd: !(!_0x4daef8.domAutomation && !_0x4daef8.domAutomationController), 
    }; 
}
沙盒检测

在此片段中,脚本通过搜索 node-onlyprocess对象来检查它是否在 NodeJS 环境中运行:

(function () { 
    SGPnwmT[SGPnwmT[0]] -= +( 
        (Object.prototype.toString.call( 
            typeof globalThis.process !== "undefined" ? globalThis.process : 0 
        ) === 
            "[object process]") === 
        false 
    ); 
    /* ... */ 
});

为了检测对本机函数的任何修改(例如,猴子修补),CloudflaretoString对它们执行以检查它们是否返回"[native code]"

c = function (g, h) { 
    return ( 
        h instanceof g.Function && 
        g.Function.prototype.toString.call(h).indexOf("[native code]") > 0 
    ); 
};

第五步:把它们放在一起

ew,到目前为止,这已经是相当不错的旅程了!我们知道,要吸收的东西太多了。让我们稍作休息,回顾一下您到目前为止所学的内容:

  • Cloudflare 反机器人的目的
  • Cloudflare 使用的主动和被动机器人检测技术
  • 什么是 Cloudflare 等候室/挑战页面
  • 如何对 Cloudflare 等候室的请求流进行逆向工程
  • 如何对 Cloudflare 挑战脚本进行去混淆处理
  • Cloudflare 如何在他们的 Javascript 挑战中实施机器人检测技术

现在,最后一步是将所有这些知识放在一起并绕过 Cloudflare!

方法 #3:使用 Cloudflare 求解器

有几种工具和库声称可以绕过 Cloudflare 挑战。有些已经完全过时,有些正在积极维护中。

有些过去可以无缝工作,但没有跟上最新的安全更新:

cloudscraper.exceptions.CloudflareChallengeError: Detected a Cloudflare version 2 Captcha challenge, This feature is not available in the opensource (free) version.

大多数选择静态绕过,而其他人,如 FlareSolverr,则采用无头浏览器方式。它在内部使用带有undetected-chromedriver的 Selenium来像普通用户一样访问目标站点。

正如它的开发者所说:“Web 浏览器消耗大量内存”。这是大多数人在不使用它们的情况下尝试这样做的原因之一。尝试使用此解决方案进行大规模抓取时要小心(下一节中有更多信息)。

方法#4:实施强化的无头浏览器

按照 FlareSolverr 的想法,您可以尝试自己运行无头浏览器。但在实施此选项之前请继续阅读。

由于无头浏览器是为测试而不是为抓取而设计的,它们有几个特征使它们很容易被 Cloudflare 识别,比如像navigator.webdriverSelenium 那样暴露。

别担心,每个最流行的无头浏览器都有解决方案:

  • Selenium: undetected_chromedriver优化和修补基础 Selenium,使其为抓取做好准备。
  • Puppeteer:使用 Puppeteer 时必须使用stealth 插件。Puppeteer extra 库带有其他有用的插件(即 adblocker 😉)。
  • Playwright:上面提到的隐形插件也适用于Playwright!

这些都是很棒的项目,如果应用了抓取补丁甚至会更好,但它们也有重要的缺点,例如上面提到的内存和资源消耗。而且,如果你不小心,带宽。

常规页面可能约为 10-50 kB,压缩后甚至更少。如果我们添加所有资源(CSS、JavaScript、图像),那很容易变成 1-5 MB。你可能需要代理,对吧?其中许多按 GB 收费;不是好消息。

您可以阻止某些资源,例如图像,因为您可能不需要它们。但阻塞时要小心;过于激进,Cloudflare 会检测到您。

需要注意的是,反机器人系统会加载某些资产来执行检查。JavaScript 是每个人都在谈论的语言,但他们不会仅限于此。有时图像和/或样式表也很重要,不加载它们是安全系统阻止您的明确指示。

方法#5:绕过 Cloudflare 的智能代理

大多数时候,花费大量时间、精力和金钱来开发和维护您自己的求解器……或者为无头浏览器使用的带宽和资源付费是不切实际的。您已经看到绕过 Cloudflare 等候室是可能的,但需要大量工作。

除了上面看到的开源求解器之外,还有其他替代方案,通常称为智能代理、反机器人 API,或者在这种情况下称为 Cloudflare 旁路代理。它将在幕后运行所需的检查和求解器以返回数据。您无需担心,花费更少的资源。

它可能适用于 API 或代理模式。您执行一个常规请求(想想一个常规的 cURL 调用),您不会浪费任何资源,只需最少的计算时间。

# pip install zenrows
from zenrows import ZenRowsClient

client = ZenRowsClient("YOUR_API_KEY")
url = "https://www.g2.com/products/asana/reviews"
params = {
   "antibot":"true",
   "premium_proxy":"true"
}

response = client.get(url, params=params)

print(response.text)
# ... <title>Asana Reviews 2023: Details, Pricing, & Features | G2</title> ...

方法#6:抓取谷歌缓存

有时,我们试图在窗户打开时强行打开门。像 Google Cache 或Internet Archive这样的网站有许多网站的副本,所以我们应该问问自己:

  • 我需要的数据在那里吗?并更新?
  • 安全级别是否低于我最初的目标?

如果这两个问题的答案都是正确的,并且之前的方法都不适合您,那么让我们试试最后一个项目符号。

您可以先在 Google 上手动搜索您的目标,看看它是否有缓存版本。单击站点域名或面包屑旁边的三点图标,它会显示如下所示的弹出窗口:

medium_image1_c1c1a12163

那里的“缓存”链接将为您提供最后一页版本。这些链接具有以下 URL:

https://webcache.googleusercontent.com/search?q=cache:gsruBfntoNQJ:https://archive.org/

您可以在抓取后忽略代码cache:并直接插入 URL。

方法 #7:Cloudflare 验证码绕过

解决 Cloudflare CAPTCHA 的任务并不便宜,但避免它们更容易、更方便。

medium_image2_e469699b30

Cloudflare 提供的具有最高安全级别的站点甚至会向使用常规浏览器的普通用户显示 CAPTCHA 检查。

这里的解决方案可能是使用像 2captcha 这样的求解器服务构建 Cloudflare CAPTCHA 绕过。这些服务会将验证码显示给真人,让他们手动解决。然后,它会返回给你解决方案,你可以继续。

但这些服务速度很慢,而且规模相当昂贵。但是您可以将它们用作所有其他方法都失败的情况的备用计划。

尝试分析和理解你的目标。一些网站只会在一周中的特定时间或特定几天使用最高安全级别。如果您可以识别它们并跳过它们,您将不需要增加 CAPTCHA 求解器的额外工作。此外,我们建议应用部分(或全部)解释的方法。

方法#8:绕过 Cloudflare 的 API

大多数时候,花费大量时间、精力和金钱开发和维护您自己的求解器是不切实际的。您已经看到绕过 Cloudflare 等候室是可能的,但需要大量工作。

DYI Cloudflare 绕过

我们已经提到这不是一件容易的事,但是您如何自己绕过 Cloudflare 等候室呢?

假设以上选项均不适用于您的用例。或者您正在研究并希望建立自己的方法。当然,您可以从所有选项中学习以及这些项目如何解决问题。要绕过 Cloudflare 的保护,您需要结合从前面部分中获得的所有知识。

如您所知,Cloudflare 有两种机器人检测方法:被动指纹识别主动机器人检测通过他们的 JavaScript 挑战)。要绕过 Cloudflare,您需要潜入他们两个的雷达之下。为了帮助您入门,这里有一些提示。

绕过 Cloudflare 被动机器人检测

  • 使用高质量的代理。要将您的爬虫伪装成合法用户,请使用住宅代理。数据中心代理和 VPN 很容易被 Cloudflare 检测到,并被归类为可疑流量。此外,来自单个 IP 地址的请求过多可能会导致阻塞,因此请务必在每个会话中轮换代理以避免这种情况。如果您仍然面临障碍,专门的Cloudflare CAPTCHA 代理将帮助您绕过它们并跳过等候室。
  • 模仿浏览器的标题。通过确保发送原始请求中的所有 HTTP 标头,使您的爬虫请求看起来尽可能真实。这包括为每个请求提供有效的 cookie 标头!
  • 匹配列入白名单的指纹。如果你决定走浏览器自动化路线,你的爬虫可能默认满足这个要求。但是,前提是您使用构建该库的确切用户代理和浏览器版本。在开发完全基于请求的抓取工具时,这会变得更加乏味。您需要捕获和分析来自您打算模拟的浏览器的数据包。您选择的编程语言是有限的。它必须有足够的低级别访问权限来控制 Cloudflare 的 TLS 和 HTTP/2 指纹识别规范的所有组件,因此您可以1:1 匹配浏览器

请记住,被动机器人检测是 Cloudflare 的第一层防御。如果你想绕过Cloudflare,这一步是不能忽略的。

如果您的活动被他们的被动机器人保护系统标记为可疑,您将立即被阻止。相反,绕过它们甚至可能会让您跳过活动的机器人保护检查。

绕过 Cloudflare 主动机器人检测

  • 重构挑战解决逻辑。这需要对 Cloudflare 等候室的内部结构有专业的了解。研究它的请求流和反混淆脚本。您需要弄清楚Cloudflare 执行了哪些检查、它们的执行顺序以及如何绕过它们。您还需要复制 Cloudflare 的各种有效载荷的加密和解密。这是创建绕过最困难的部分,因为 Cloudflare 挑战脚本是动态的。每个会话甚至可能需要您即时对新脚本进行去混淆处理,以解析特定值以供您的求解器使用。
  • 收集真实设备数据。即使您完全了解它们是如何制作的,有些指纹也太不切实际而无法尝试冒充。例如,Cloudflare 的 Canvas 指纹识别。与 TLS 或 HTTP/2 指纹不同,它在很大程度上依赖于软件和硬件的移动部件。硬件组件的功能太先进了,无法尝试和模仿,而不是你想要花所有时间为抓取项目设计的东西。相反,考虑从真实用户的设备收集指纹数据。然后,您可以在需要使用这些数据时将其注入求解器。但是你不会只用几个。您最好的选择是在高流量网页上托管一个收集器以确保您有足够的设备以避免对 Cloudflare 的机器学习系统产生怀疑。
  • 使用自动浏览器/沙盒脚本。如果您想抽象一些解决挑战的逻辑,您可以考虑直接执行 Cloudflare JavaScript 挑战。这可以在浏览器中使用自动化工具或通过在 JSDOM 等沙箱中模拟浏览器来实现。这种方法的缺点是性能。运行或模拟浏览器环境将比基于请求/算法的挑战求解器慢得多且计算成本高。另外,请记住 Cloudflare 会检查自动浏览器和沙盒。要绕过它们,您首先必须了解哪些存在以及它们是如何工作的。因此,无论沙盒与否,您都无法跳过对 Cloudflare 挑战脚本的去混淆处理!您可以实现无头浏览器 Cloudflare 绕过,但需要一些努力。

如果你已经走到这一步,那就太棒了!您现在已经熟悉了为 Cloudflare 的反机器人挑战制作求解器的过程。

如果您发现自己在这个过程中感到迷茫,请不要担心。我们明白了,绕过任何反机器人都是一项艰巨的任务。但这并不意味着您应该放弃您的抓取项目!

从头开始绕过 Cloudflare 是一项复杂的任务,如果您打算自己动手,则没有任何捷径可走。但这并不一定如此困难!有时,最好让别人替您处理。

结论

感谢你的阅读!我们知道这是一篇冗长的文章,但 Cloudflare 的高度复杂性使其成为必要。

谢谢阅读!我们希望本指南能帮助您了解有关 Cloudflare 的机器人检测技术、如何对其进行逆向工程以及最终如何绕过 Cloudflare 等候室的宝贵知识。您今天学到的方法也不仅仅是 Cloudflare 特有的:您可以回过头来帮助绕过其他反机器人程序!

常见问题

是否可以绕过 Cloudflare?

是的,可以绕过 Cloudflare。它的反机器人技术可以分为两种,即被动指纹识别和主动反机器人检测。因此,要绕过 Cloudflare,您必须找到绕过它们的方法。

为什么我的 IP 会被 Cloudflare 封禁?

如果您表现出类似机器人的行为,例如快速发出过多请求、使用非浏览器用户代理等,Cloudflare 可能会阻止您的 IP。另一个原因可能是您的 IP 因与可疑活动相关联而被列入黑名单。

你如何打败 Cloudflare?

你可以通过强化你的网络抓取工具来打败 Cloudflare,让请求看起来像是来自真实用户。其他方法包括:

  • 逆向工程 Cloudflare 的反机器人挑战。
  • 抓取谷歌缓存。
  • 将您的请求直接发送到源服务器。
  • 使用智能代理。

类似文章