如何绕过DataDome保护的网站
不幸的是,许多网站已经实施了先进的反机器人程序,例如 DataDome,以防止网页抓取。好消息是您将在本指南中学习如何绕过 DataDome,包括:
什么是 DataDome?
DataDome是一个完整的反机器人套件,可轻松与流行的框架和平台(如 Amazon CloudFront、Nginx、Salesforce 和 Kubernetes)集成。它是真实或看似网络威胁的领先提供商,包括 DDoS 攻击、爬虫、SQL 或 XSS 注入以及卡和支付欺诈。
DataDome 如何检测机器人?
DataDome 使用服务器端和客户端技术来检测已知和未知的机器人程序:用户行为、网络和浏览器指纹、地理位置跟踪等。DataDome 还定期更新和维护其数据集,以跟上不断发展的机器人环境。
让我们学习每种类型最重要的技术,作为学习如何绕过 DataDome 的第一步。
服务器端措施
服务器端措施依赖于分析与服务器的连接、浏览会话和所有相关元数据。他们利用围绕浏览会话的协议规范(如 HTTP、TCP 和 TLS)对用户进行指纹识别并查找不一致和可疑行为。
HTTP/2 指纹识别
HTTP/2 是一种二进制协议,它将数据作为流中的帧发送。它的主要目标是通过引入标头字段压缩并允许在同一 TCP 连接上进行并发请求和响应来提高网站和 Web 应用程序的性能。
TCP/IP 指纹识别
联网设备将从第一个 TCP/IP 请求开始指示其特性。作为 TCP 三向握手的一部分,使用 TCP SYN 数据包启动 TCP/IP 连接。在这个特定的数据包中,客户端将提供基本参数,例如生存时间 (TTL) 和对IP 分段的支持。
TLS 指纹识别
TLS fingerpriting是一种服务器端技术,Web 服务器使用该技术在任何应用程序数据交换发生之前仅使用第一个数据包连接中的参数来确定 Web 客户端的身份(浏览器、CLI 工具或脚本)。
服务器端行为
该技术根据来自服务器的日志分析浏览会话和导航,例如请求、执行和尝试的操作、IP 地址以及与蜜罐的交互。监视此数据是否存在异常和异常值:如果请求的频率太高,则可以对其进行速率限制;如果请求的来源国在浏览会话期间发生变化,则表明代理已激活。
客户端信号
客户端信号是从最终用户设备收集的信号。它们可以使用 JavaScript (JS) 在浏览器中收集,也可以使用 SDK 在移动应用程序中收集。一些用于客户端信号的技术是:
操作系统和硬件数据
从历史上看,操作系统指纹识别是最有价值的,特别是对于寻找易受攻击的操作系统版本的攻击者而言。它包含有关 CPU、GPU、笔记本电脑或手机型号、设备供应商和制造商的详细信息。操作系统细节有些静态,不太可能随时间变化。如果我们比操作系统低一级,它会把我们带到硬件数据,这更难改变。
如果您对该数据感兴趣,可以在开发者控制台中执行以下 JavaScript:
console.log("OS: " + navigator.platform); console.log("Available RAM in GB: " + navigator.deviceMemory); document.body.innerHTML += '<canvas id="glcanvas" width="0" height="0"></canvas>'; var canvas = document.getElementById("glcanvas"); var gl = canvas.getContext("experimental-webgl"); var dbgRender = gl.getExtension("WEBGL_debug_renderer_info"); console.log("GL renderer: " + gl.getParameter(gl.RENDERER)); console.log("GL vendor: " + gl.getParameter(gl.VENDOR)); console.log("Unmasked renderer: " + gl.getParameter(dbgRender.UNMASKED_RENDERER_WEBGL)); console.log("Unmasked vendor: " + gl.getParameter(dbgRender.UNMASKED_VENDOR_WEBGL));
输出将类似于以下内容:
OS: Linux x86_64 Available RAM in GB: 2 GL renderer: WebKit WebGL GL vendor: WebKit Unmasked renderer: NVIDIA Corporation Unmasked vendor: NVIDIA GeForce GTX 775M OpenGL Engine
值得注意的是,在移动应用程序和 SDK 的上下文中,操作系统和硬件指纹识别要有效得多,并且可以访问全球持久性数据,例如 MAC 地址或国际移动设备标识 (IMEI )。
浏览器指纹识别
浏览器指纹识别是一种用于通过收集有关浏览器的各种信息
如浏览器类型和版本、屏幕分辨率和 IP 地址)来唯一标识 Web 浏览器的技术。此信息创建一个独特的“指纹”来跟踪不同网站和会话的浏览器。
浏览器指纹识别中采用的一些技术是画布指纹识别、音频指纹识别、存储和持久跟踪以及媒体设备指纹识别。
行为数据
这些数据是在用户与网站或应用程序交互时生成的。它们可能来自移动鼠标、单击、触摸屏幕、快速打字或使用传感器(如设备中的加速度计)等手势。
那么 DataDome 是如何通过这些方法获得成功的呢?
DataDome 如何使用这些技术?
DataDome 的机器人检测引擎是一个能够使用上面共享的检测技术做出快速决策的系统。它们分为 3 层:
- 经过验证的机器人程序和自定义规则:根据直接属性(如源 IP 地址、源域或用户代理)允许/阻止请求的清晰简单的规则。这是经过验证的机器人,如谷歌的爬虫,毫无疑问地被允许进入的地方。
- 基于签名的机器人检测:指纹的合成被简化为即时检查的签名。这条防线是大多数机器人程序被捕获的地方:自动浏览器、代理、虚拟机和模拟器。
- 机器学习检测:这一层从它输入的信号中学习,并获取机器人行为的微妙指标。这些机器学习算法不断地从收集到的所有信号中学习,并可以识别设备如何呈现自身的矛盾。即使是使用配置良好的自动浏览器并使用住宅 IP 构建的高级爬虫,也可能在这个级别被捕获。
DataDome Antibot 系统逆向工程
当今的 Antibot 系统复杂且多层次,DataDome 也不例外。要绕过 DataDome,您需要对其进行逆向工程。我们将检查以下内容以获得全面的方法:
- DataDome 的验证码。
- DataDome 网络请求。
- 逆向工程 DataDome 的 JavaScript 文件。
DataDome 的验证码挑战
为了触发 DataDome 的反机器人机制,我们将使用Playwright尝试访问Vercel DataDome 模板。这将触发一个页面,说明我们的浏览器显示带有验证码的可疑行为,如果您仔细查看源代码,您会注意到它是从GeeTest加载的。
让我们使用 PuppeteerJS 和一些OpenCV.js魔法绕过它。比较图像并分析它们的轮廓,然后计算滑块需要移动多少才能解决难题,最后任务 Puppeteer 移动滑块:
我们之前介绍的所有行为数据和鼠标移动呢?这就是放弃我们的自动浏览器的原因吗?让我们重试同样的事情,但这次我们将协助我们的机器人并在解决方案期间稍微移动鼠标:
闲置的鼠标泄露了我们的机器人。
但是,如果我们的 DataDome 绕过解决方案需要手动干预来移动鼠标,那能算高效吗?不。首先,机器人不应该触发 CAPTCHA 挑战,这只是 DataDome 使用的现代 CAPTCHA 如何将附加数据信号与检测机器人的解决方案相关联的一个例子。
DataDome 网络请求
网络请求始终是检查 JavaScript 文件如何获取以及其他向 DataDome 服务器发出的请求的良好起点。要对我们的 DataDome 绕过进行逆向工程,请启动浏览器并打开开发人员工具。然后,切换到“网络”选项卡并导航到受 DataDome 保护的网站。
与 DataDome 相关的第一个请求是GET
获取 JavaScript 文件的请求https://js.datadome.co/tags.js
网络请求获取 DataDome 的 JS 文件
作为混淆的一部分,这些文件会因请求而异,以混淆任何试图理解它们的人。这是使用实时多态 JavaScript 混淆实现的,它随机化 JavaScript 混淆器的输出。
在我们的例子中,脚本文件保持静态,但在不同来源和不同时间请求时会发生变化。幸运的是,这不算是多态 JavaScript 混淆,只是随机生成的名称。
对 DataDome 服务器的第二个传出网络请求是一个具有相当大负载的POST
请求https://api-js.datadome.co/js/
:
DataDome 跟踪网络请求的负载
它的有效负载包含多个参数,但其中最值得注意的是:
- jsData:用于根据许多参数对访问受保护页面的浏览器进行指纹识别。DataDome 的服务器将检查此数据是否一致,是否与机器人的签名匹配,并使用它来跟踪导航和行为。
- events:脚本捕获的一系列事件,例如鼠标移动、滚动和键盘输入。
- eventCounters:它可以单独用作数据信号或检查报告事件的完整性。
- ddk:标识 DataDome 客户端的键。
- Referer:发出请求的地址。
如果一切顺利,对该请求的响应将包含一个名为 的 cookie datadome
,它将在后续请求中作为许可证明提供。
反混淆 JavaScript 挑战
由于客户端措施依赖于在用户设备中运行脚本,因此它们必须与受保护的网站或应用程序一起提供。这些脚本包含专有代码并使用模糊处理进行保护。这些措施可能会使逆向工程变得更加复杂和缓慢,但并非不可能。
开始使用在线 JavaScript 去混淆器,例如DeObfuscate.io,然后前往https://js.datadome.co/tags.js
DataDome 托管其脚本的地方。JavaScript 反混淆器将变量重命名为更人性化的格式、抽象代理函数并简化表达式。
一些混淆技术不容易逆转,需要您比自动化工具更进一步。
让我们逐步了解这些技术。
字符串隐藏
变量和函数被重命名为无意义的名称以降低脚本的可读性,所有对字符串的引用都被替换为十六进制表示。除了重命名和编码之外,它们还使用字符串隐藏功能进行隐藏。
larone()
是脚本中函数的一个示例,因为它在脚本中被调用了 1200 多次,并且包含从“a”到“z”的字母字符和三个特殊符号,表示字符操作。在整个代码中,这个函数经常会被重新分配给一个变量来混淆调试。
当使用整数作为参数调用时,它会返回一个字符串,该字符串将揭示函数调用和变量名称。将其用法转换为相应的函数将是反混淆的重要一步,所以让我们看看这个函数在文件中的每次调用都返回什么。
您可以在浏览器的开发人员控制台中设置一个断点,其中所述函数将可用,window.larone
并编写一个简单的循环来生成参数到字符串输出的映射:
字符串隐藏函数反混淆字典
之后,我们将编写一个脚本,用等效的字符串替换larone()
对 JS 文件中函数的调用。这将语句 like 变成document[_0x3b60ec(132)]("x63x61x6ex76x61x73")["x67x65x74x43x6fx6ex74x65x78x74"](_0x3b60ec(406));
更具表现力的语句,例如document.createElement("canvas").getContext("webgl");
。
在将这些十六进制标识符转换为人类可读的版本并替换字符串隐藏功能后,我们能够解决的一些难题是验证码、请求的有效负载POST
、DataDome JS 密钥和 Chrome ID。
在运行时编辑变量
脚本中的一个重要问题是大量的神秘值。按照它的使用位置,我们可以看到脚本中的第一个自调用函数。它通过将第一个元素移动到最后一个位置来打乱数组,直到表达式等于第二个整数参数:
(function (margart, aloura) { var masal = margart(); while (true) { try { var yasameen = (parseInt(larone(392)) / 1) * (-parseInt(larone(713)) / 2) + (-parseInt(larone(390)) / 3) * (-parseInt(larone(606)) / 4) + parseInt(larone(756)) / 5 + (-parseInt(larone(629)) / 6) * (-parseInt(larone(739)) / 7) + (-parseInt(larone(679)) / 8) * (parseInt(larone(426)) / 9) + parseInt(larone(385)) / 10 + (parseInt(larone(362)) / 11) * (-parseInt(larone(699)) / 12); if (yasameen === aloura) break; else masal.push(masal.shift()); } catch (prabh) { masal.push(masal.shift()); } } })(jincy, 291953);
通过设置一个方便的断点并为上面的函数添加一个计数器,我们看到它被调用了大约 300 次。
此函数的唯一目的是编辑加密全局变量,直到该yasameen
变量评估第二个整数参数。它通过将第一个元素移动到最后一个位置来重组它。这发生在运行时,可能会使读者在尝试解密隐藏的字符串时迷失方向。
控制流混淆
开发人员喜欢按职责来组织代码,例如数据、业务逻辑、HTTP 库、加密等。这使我们能够分离关注点,并便于跟踪执行流程,尤其是在调试时。
好的代码是可读的,混淆器知道这一点,因此他们使用控制流混淆来利用它。此过程重新安排指令,使人类难以遵循脚本的逻辑。如果脚本是用这种技术编译和混淆的,它甚至会使试图理解它的反编译器崩溃。
在我们的例子中,脚本中的 main 函数大量使用递归和嵌套调用来模糊执行路径。main()
这在函数及其定义的函数中很明显executeModule()
。我们还将变量重命名为更具表现力的名称:
!(function main(allModules, secondArgument, modulesToCall) { function executeModule(moduleIndex) { if (!secondArgument[moduleIndex]) { if (!allModules[moduleIndex]) { var err = new Error("Cannot find module '" + moduleIndex + "'") } } // ... allModules[moduleIndex][0].call( // ... function (key) { return executeModule(allModules[moduleIndex][1][key] || key); }, // ... main, modulesToCall // ... ); } return secondArgument[moduleIndex].exports; } for (...) executeModule(modulesToCall[i]); return executeModule; })(...)
弄清楚这些功能的执行流程一点也不简单。我们怀疑它会编排所有执行和处理 JavaScript 模块。为什么?Cannot find module
因为上面代码中的错误信息泄露了它。
注意:这可能是由于控制流混淆或只是标准的 JS 模块捆绑。但它确实混淆了我们对脚本的理解,因此我们将其视为混淆。
分析反混淆脚本
到目前为止,我们已经能够剥离相当多的混淆层以了解如何绕过 DataDome。现在是退后一步,鸟瞰脚本的时候了。该脚本包含三类,分别是全局变量、字符串隐藏函数和函数main
:
// Global variables, with import paths as keys and small integers as values ... var global3 = { "./common/DataDomeOptions": 1, "./common/DataDomeTools": 2, "./http/DataDomeResponse": 5, } var global4 = {...} // ... // First self-invoking function to shuffle global array defined below (function (first, second) { ... })(globalArray, 123456) // String-concealing function function concealString(first, second) { // ... } // Global array of 500+ cryptic strings globalArray = [ "CMvZB2X2zwrpChrPB25Z", "AM5Oz25VBMTUzwHWzwPQBMvOzwHSBgTSAxbSBwjTAg4", // ... ] // Main function !(function main(first, second, third) { // Orchestrate JavaScript module passed in first argument })( // Nine JavaScript modules, { 1: [ function () {}, global1, ], 2: [...], // ... } {}, [6], // Entrypoint module )
我们的分析将集中在主要功能上。您会注意到它有一个实质性的第一个参数,并且文件的大部分代码都单独在这个参数中。第一个参数是一个遵循特定模式的对象,对象的每个值都是一个包含 2 个元素的数组:一个具有三个参数的函数和一个全局对象。
大多数模块辅助机器人检测和处理事件跟踪、HTTP 请求和字符串处理。我们会将这些留给您自己发现。至于bot detection,与之相关的模块有:
- 模块 1:它初始化 DataDome 的选项,如
this.endpoint
,this.isSalesForce
和this.exposeCaptchaFunction
。它还定义并运行一个名为this.check
. 此函数加载所有 DataDome 选项,并在入口点模块的早期调用。 - 模块 3:这是进行指纹识别的地方。它定义了超过 35 个函数,名称以 为前缀
dd_
,并异步运行它们。这些功能中的每一个都收集一组指纹识别信号。例如,指示使用 PhantomJS 的函数this.dd_j()
和检查窗口变量。this.dd_k()
- 模块 6:它是函数的最后一个参数
main()
。它加载 DataDome 选项(使用模块 1)并启用事件跟踪(使用模块 7 和 8)。
DataDome的指纹数据
让我们看看 DataDome 收集的数据,它与前面提到的指纹识别方法有什么关系,以及它是如何收集到 JavaScript 文件中的。为此,我们会将请求的有效负载HTTP POST
与去混淆处理的结果进行匹配。
我们将从POST
有效载荷属性glrd
和开始glvd
,分别代表 WebGL 渲染器和供应商信息。这属于浏览器指纹数据,这就是 DataDome 的脚本收集它的方式。
webgl_context = document.createElement("canvas").getContext("webgl") webgl_info = webgl_context.getExtension("WEBGL_debug_renderer_info") jsData.glrd = webgl_context.getParameter(webgl_info.UNMASKED_RENDERER_WEBGL) jsData.glvd = webgl_context.getParameter(webgl_info.UNMASKED_VENDOR_WEBGL)
关于访问者的另一个数据点是安装的浏览器插件。这些在用户之间是高度个性化的,它们不会经常更改并且对于自动浏览器来说是空的。这个小的 JavaScript 循环收集已安装插件的名称及其总数,类似于 DataDome 所做的:
var plugins = [] for (i = 0; i < window.navigator.plugins.length; i++) plugins.push(window.navigator.plugins[i].name) jsData.plg = plugins.length jsData.plu = plugins.join()
DataDome 在有效载荷中收集 30 多个数据点jsData
,具体取决于设备、外围设备、使用的显示器、浏览器和地理位置。下面是一个数据示例,附带来自 DataDome 的反混淆 JavaScript 的相应 JavaScript 表达式:
{ "rs_h": 1080, // window.screen.height "rs_w": 1920, // window.screen.width "rs_cd": 24, // window.screen.colorDepth "phe": false, // window._phantom "nm": false, // window.__nightmare "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36", // window.navigator.userAgent "lg": "en-GB", // navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || ""; "ars_h": 1053, // screen.availHeight "ars_w": 1848, // screen.availWidth "str_ss": true, // window.sessionStorage "str_ls": true, // window.localStorage "str_idb": true, // window.indexedDB "str_odb": true, // window.openDatabase "mmt": "application/pdf,text/pdf", // window.navigator.mimeTypes "plg": 5, // Number of plugins "eva": 33, // eval.toString().length "ts_tec": false, // touch event create "ts_tsa": false, // "ontouchstart" in window "vnd": "Google Inc.", // window.navigator.vendor "bid": "NA", // window.navigator.buildID || "NA" "tzp": "Europe/Paris", // Intl.DateTimeFormat().resolvedOptions().timeZone "cvs": true, // Boolean(document.createElement("canvas").getContext("2d")) "dcok": ".coingecko.com" // window.location.hostname }
现在我们已经对其反机器人系统进行了逆向工程,让我们继续创建一个 DataDome 旁路解决方案!
如何绕过 DataDome 机器人检测
为了绕过 DataDome 的保护,我们将结合您从前面部分中获得的所有知识。如您所知,它在服务器端和客户端使用机器人检测技术,例如 TLS 指纹识别和浏览器指纹识别。要创建 DataDome 绕过措施,您将潜入这些技术的雷达之下并提取数据。
以下是一些方法:
自动浏览器
自动化浏览器,如Selenium和Puppeteer,是为自动化目的而创建的工具,因此,它们毫不费力地隐藏自己的本性。要绕过 Python(或任何其他框架)中的 DataDome,请使用掩码包,例如用于Puppeteer 的puppeteer-extra-plugin-stealth 、用于 Selenium 的selenium-stealth或用于 Playwright 的playwright-stealth。
这些浏览器及其扩展可能不同,但它们背后的技术都是相同的。这些扩展处理浏览器指纹中的不一致,覆盖浏览器 JavaScript 变量并删除特定于自动浏览器的全局变量。
质量代理
代理对于网络抓取至关重要,因为它们隐藏并保护您的 IP 地址,使您能够绕过 DataDome 机器人检测并提取数据。有不同的网络抓取代理可供使用,但绕过 DataDome 最有效的代理是数据中心和住宅代理。
考虑静态代理和旋转代理也很重要:静态代理提供恒定的 IP 地址,因此发送过多的请求会导致检测。绕过 DataDome 检测的最佳方法是轮换代理。
验证码绕过
- 自动验证码求解器:能够为挑战提供快速解决方案。它们基于光学字符识别 (OCR) 和对象检测等机器学习技术。
- 人工:手动解决所有验证码并为您提供响应的团队。它既慢又贵,但它是解决验证码的可靠方法。
但让我们现实一点:让你的抓取工具访问 CAPTCHA 是个坏主意,因为它会减慢抓取过程并增加成本。最好的方法是使用CAPTCHA 代理完全绕过 DataDome CAPTCHA 。一个好的代理验证码必须快速、可扩展并且能够在不影响速度的情况下支持不同的渲染。
网页抓取API
虽然共享的技术对于绕过 DataDome 是有效的,但花费大量时间、精力和金钱来开发和维护它们是不切实际的。DataDome 绕过的一个更直接的解决方案是使用能够避免反机器人的工具。
结论
在本文中,我们介绍了 DataDome 僵尸程序检测系统的技术,对反僵尸程序进行了逆向工程,并讨论了一些 DataDome 绕过技术。
回顾一下,绕过 DataDome bot 检测的方法是:
- 使用自动浏览器。
- 使用质量代理。
- 使用验证码旁路服务。
- 使用网络抓取 API。
虽然这些方法很有效,但它们可能成本高昂且压力大,而且在缩放时仍有可能被检测到。避免这种情况的最佳方法是使用可有效绕过 DataDome 和其他反机器人的网络抓取工具,您可以开始免费对其进行测试。