用一个奇招检测并让Chromium机器人爬虫崩溃(机器人爬虫讨厌这个!)

免责声明:如果你是来寻找机器人检测的终极解决方案,这可能不是你要找的,除非你的用户体验策略涉及弹出窗口,而你的营销策略涉及阻止Google爬虫。

我们最近在Chromium的漏洞追踪器上发现了一个漏洞,一个简短的JavaScript片段可以让无头Chromium浏览器(如Puppeteer和Playwright所使用的)崩溃。听起来像是检测机器人的理想信号,对吧?检测机器人,让他们的浏览器崩溃,这一切都可以在客户端JS中实现,无需服务器。如果你足够幸运,甚至可能在他们的服务器上引发内存泄漏!

也许吧。也许不。在这篇文章中,我们将分解这个漏洞,探讨它如何被用于检测,最后解释为什么这可能不是在生产环境中使用它的一个好主意。

分析漏洞报告

元素周期表漏洞追踪器不仅仅是让工程师感到沮丧的工具——它们是机器人猎人的宝库。每个无头浏览器的怪癖或自动化漏洞都可能是检测信号。如果在 Puppeteer 中出现问题但在 Chrome 中正常,那值得进一步调查。

这个漏洞简单而精妙。在 iframe 上调用 contentWindow.open 并传入特定参数,浏览器就会崩溃。在 Puppeteer 和 Playwright 中均可完全复现:

const iframe = document.createElement("iframe");
iframe.src = "data:text/html,<body></body>";
document.body.appendChild(iframe);
iframe.contentWindow.open("", "", "top=9999");

为了演示,这里是一个Playwright机器人访问Hacker News、截取屏幕截图,然后触发崩溃的示例:

import { chromium } from "playwright";

(async () => {
    const browser = await chromium.launch({ headless: false });
    const context = await browser.newContext();
    const page = await context.newPage();
    
    await page.goto('https://news.ycombinator.com');
    
    await page.waitForTimeout(1000);
    await page.screenshot({ path: 'screenshot.png' });
    
    try {
        await page.evaluate(() => {
            const iframe = document.createElement("iframe");
            iframe.src = "data:text/html,<body></body>";
            document.body.appendChild(iframe);
            iframe.contentWindow.open("", "", "top=9999");
        });
    } catch (error) {
        console.log(error);
    }
    
    await browser.close();
})();

需要注意的是,try/catch块没有任何作用。没有异常被抛出。对page.evaluate的调用只是挂起,浏览器会静默崩溃。browser.close()从未被调用,这可能会导致内存泄漏。

 

创建终极机器人检测信号?

注意问号。别太兴奋。

以下是 botCheckMate 的代码,我们的不完美检测器:

function botCheckMate() {
	const iframe = document.createElement("iframe");
	iframe.src = "data:text/html,<body></body>";
	document.body.appendChild(iframe);
	iframe.contentWindow.open("", "", "top=9999");
	
	// After this point, if the code didn't crash, then you're human
	return false;
}

let isBot = botCheckMate();

如果你是人类,这会返回 false。如果你是基于 Chromium 的机器人,你会崩溃,而我们保存了返回值!#效率至上

你可以在浏览器开发工具中运行此代码进行验证,它将返回 false。如果你使用 Puppeteer 或 Playwright(基于 Chrome)运行,你的浏览器将崩溃。

为什么这是一个在生产环境中糟糕的主意

尽管本文的语气明显是开玩笑的,但有一个严肃的启示:并非所有检测信号都适合在生产环境中使用。这个检测信号尤其存在诸多缺点,其弊端远大于其新颖性。

首先,触发弹出窗口给人类用户绝非明智之举。大多数人不会预期(或希望)在浏览过程中突然弹出未经请求的窗口。这会破坏用户预期、中断其操作流程,并几乎肯定会降低用户体验。坦白说,你的CMO可能也不会对此感到高兴。

其次是副作用问题。构建机器人检测系统时,尤其是我们Castle团队的做法,核心原则是尽量减少影响。我们倾向于使用安静且不易察觉的信号,避免记录噪音事件、占用过多CPU资源或触发控制台警告。而这种检测方法?它就像在数字世界里大声喊叫。

另一个重大担忧是检测与响应之间的紧密耦合。虽然将两者合并看似诱人,尤其是当响应效果如此令人满意时,但这通常并非正确做法。良好的机器人检测意味着将检测与后续行动分离。你可能希望阻止用户、对其进行影子禁令、标记其账户以供审核,或完全不采取行动。但一旦你让用户的浏览器崩溃,选择就已经做出。

此外,由于整个策略在客户端执行,你将失去大部分可用于决策的有用元数据。你无法在服务器端存储机器人签名、管理Googlebot或自有质量保证工具的允许列表,也无法根据威胁级别定制响应。

最后,机器人会进化。一旦机器人作者弄清楚导致崩溃的原因,他们就会覆盖open()方法或对参数进行 sanitization。游戏结束。您又回到了检测军备竞赛中。想深入检测覆盖操作?我们已通过如《画布随机化》文章中所述的技术为您提供支持。但这意味着您将陷入一场彻头彻尾的猫鼠游戏,伴随着所有随之而来的维护工作。

因此,是的,这个信号有效。但并非没有限制,更不用说没有成本了。

结论

从理论上讲,这种检测方法看起来非常吸引人。只需几行 JavaScript 代码,就能轻松识别并屏蔽机器人浏览器。这种方法简洁、有效,甚至让人感到一种奇妙的满足感。然而,在实际应用中,情况要复杂得多。

最佳的检测信号不仅要有效,还要悄无声息地工作。它们不会降低性能或损害用户信任。它们允许你根据上下文做出决策,而不仅仅是在条件满足时立即触发不可逆的操作。最重要的是,它们能够抵御适应性变化。

这种信号虽然在演示中令人捧腹且强大,但它不符合上述任何标准。它过于显眼。它侵入性强。它脆弱易碎。

所以,享受这个漏洞吧。把它留在你的工具箱里。在测试环境中让机器人崩溃时笑一笑。但也许不要在生产环境中部署它。尤其是当Googlebot能看到它的时候。

除非你已经不在Google的搜索索引中。那么,当然,尽情发挥吧。

共有 52 条讨论

  1. > 调用 page.evaluate 时会卡住,浏览器会静默关闭。browser.close() 方法从未被调用,这可能导致内存泄漏。

    不仅仅是内存泄漏。自几个月前起,若在 macOS 上通过 Playwright 等工具使用 Chrome,系统会将 Chrome 的副本(超过 1GB)存储至 /private/var/folders/kd/<…>/X/com.google.Chrome.code_sign_clone/ 目录中。若未通过 browser.close() 正常退出,该 Chrome 副本将持续存在。我发现其在两天内占用了约 50GB 空间。我不清楚这个代码签名克隆功能的用途,但不得不为所有调用添加 –disable-features=MacAppCodeSignClone 参数来阻止它,这非常烦人。

    1. 目前这是一个已知问题,但值得庆幸的是,这些克隆文件是 APFS 格式,因此不会实际占用磁盘空间。

      1. 有趣的是,依稀记得我删除所有克隆时确实释放了不少磁盘空间,但当时也删除了大量其他文件,所以可能记错了。由于 du(1) 无法识别 APFS 克隆,因此难以判断。

  2. 查看https://issues.chromium.org/issues/340836884,我有点惊讶地发现该报告距今不到一年,且完全未被关注(除了四个月后的一条附和评论),尽管该问题以P1优先级提交,据我所知这意味着“力争在30天内修复”。如果该问题继续无人问津,我好奇它是否会在五天后自动提升优先级,因为他们对P2和P3级别的漏洞会采取类似措施,将状态调整为“可用”或其他状态,具体细节我记不太清了。

    我之所以说“轻微”,是因为我对Chromium漏洞的体验(无论是我自己提交的,还是遇到他人提交的)从未很好。我发现Firefox在修复漏洞方面要好得多。

      1. 公平地说,那个漏洞只是P3级别。

  3. 我认为“不让谷歌爬虫看到这个”有点好笑,毕竟谷歌搜索结果往往更糟糕。验证码/反爬虫措施已经糟糕到我不得不切换到Kagi来屏蔽某些域名,因为浏览现代网页有时几乎不可能。为什么谷歌不降低这种体验的排名?

  4. 在谷歌浏览器中,至少我尝试过通过无限循环修改document.title,结果导致其他标签页的页面也冻结。现在我不在电脑旁,无法再次尝试。

  5. 我个人觉得“无头浏览器”的存在本身就很滑稽。JavaScript解释器用于渲染网页,这不过是又一个有趣的巧合。“无版本HTML”哈哈哈

    1. 它存在是因为广告技术提供商和 CDN 惩罚那些不在其平台上执行未经信任代码的合法用户。

      1. 无头浏览器存在是因为广告技术提供商和 CDN 惩罚那些不在其平台上执行未经信任代码的合法用户?

        如果我们问无头Chrome或Selenium的创建者为何创建它们,他们会说“因为广告技术提供商和CDN会惩罚那些不在其平台上执行未经信任代码的合法用户”吗?

        1. 无论是否属实,人们决定做某事的原因与他们声称做某事的原因不必一致。

    1. 目的是让机器人的浏览器崩溃,而不是用户的浏览器

      1. 请指给我一个100%准确的机器人检测系统,且零误报。

        1. 你明白意图与现实的区别吧?

          文章甚至警告过这个副作用。

        1. 如果你在我的robots.txt中抓取禁止的数据,我不在乎。我将随意干扰你的机器人,并且愿意不惜一切代价教你尊重我的robots.txt文件。

          1. 那么我将教你一课,关于试图将公共数据私有化。住宅代理和头部浏览器会发出嘶嘶声。

            1. 恶意软件安装与导致运行抓取进程的.exe文件发生段错误是完全不同的两件事。

              如果非法抓取行为是机器的预期行为,那么机器所做的事情已经受到《计算机欺诈法》的规制。

              1. 以下几点需要注意:

                不确定《计算机欺诈法》适用的司法管辖区是否已认定存在“非法抓取”这一行为。

                《计算机欺诈法》是否涵盖导致.exe文件段错误的行为?我不知道,因为我并不生活在该法律适用的国家。

                如果《计算机欺诈法》规定允许导致.exe文件段错误(我对此表示怀疑),那么实施这种段错误操作的组织是否在作为防范所谓“非法抓取”的措施时,会核实被段错误的机器是否均位于受《计算机欺诈法》管辖的司法管辖区内?

                如果他们在这些管辖范围外引发段错误,而当地有其他适用法律,会发生什么?我猜他们可能就完蛋了。早该想到这一点,这么聪明的人。

                嘿,我明白,我就是那种可能会决定对那些通过爬取我的网站并無視我的robots.txt文件而让我损失大量金钱的人引发段错误的人。我就是这么报复心强。但我会接受,我所做的事情可能在某些地方是违法的,可惜了,我肯定不会到处辩解说这是完全合法的,我也会接受这样一个可能性:我跳入的这场斗争可能会造成一些附带损害——他们倒霉了。

                这里其他人似乎都觉得自己有理由摧毁别人的东西作为报复,而那些电脑被摧毁的人可能甚至不知道他们和你有什么恩怨。

                编辑:显然,一旦事情闹到法庭或媒体,我会辩称这是完全合法、合乎道德且正确的做法,以防止这些人继续用他们的“非法抓取”行为攻击其他网站。因为如果我因获胜而受到惩罚,我就没有赢得这场战斗。我只是在谈论在赢得战斗的过程中,要清楚自己到底在做什么。

            2. 这不是我的问题。问题将由恶意软件创建者承担。两次。

        2. 如果你从robots.txt中禁止的目录崩溃某个浏览器,这不是你的错。

            1. > 如果你不熟悉这个,去了解一下,原因可能相当发人深省

              这些原因与无头网页浏览器相关吗?

              1. 有些情况肯定不相关,有些情况则可能相关。

            2. 因为人们可能会受到伤害。

              哪些人可能会因为运行机器的崩溃而受到伤害?

              1. 当这些人决定抢劫你的家时,他们就失去了不受伤害的权利,我认为。当然,还要考虑比例原则等因素。

        3. 如果情况如此,我们该如何处理那些在网站或应用中禁用返回按钮(手机的直接返回按钮)或右键功能(桌面浏览器)的情况?而这种功能禁用并未在服务条款中提及,甚至在访问网站或使用应用时未向用户展示?

    2. 那么也许我们需要法律来规范每分钟不停地爬取服务器163,000次,無視robots.txt的行为?在此之前,对机器人没有同情。

      1. 如果你的软件因正常使用而崩溃,那只能怪你自己

        1. 没错。由于AI公司不断轰炸我的服务器导致Nginx内存不足,这是我的错。

          1. 没错。修改你的配置,确保它不会尝试分配超过你实际拥有的内存。你可以对它们轰炸你的网站感到不满,但如果你的服务器软件因此崩溃,那是一个配置错误,你应该无论如何都去修复它。

            1. 请告诉我,我应该如何配置 NGINX,以便它能够正常为所有希望访问我网站的真实人类提供服务,而不会因那些愚蠢的机器人而崩溃?

              1. 试着重新阅读上面的内容,而不是编造自己的幻想。

      1. 当然不是,为什么你一上来就跳到指责?如果我是,我只会本地修复漏洞并感谢楼主指出他们是如何做的。

        这显然是违法的,我不想让任何人陷入法律麻烦

    1. 你如何应对常见的CF、Akamai和其他指纹识别及封锁措施?还是说这是客户需要自行解决的问题?

      1. 感谢你的提问!这取决于你运营的规模。

        1. 对于个人使用(或公司使用但每个用户使用自己的设备),通常流量会被常规用户活动淹没,因为我们使用相同的浏览器,无需特殊措施,它就是这样工作的。我们为高级用户提供选项。

        2. 对于大规模使用,我们根据遇到的反机器人措施提供定制解决方案。其中一部分是模拟#1。

        3. 我们不处理“黑帽机器人”,因此不提供绕过合法反机器人措施(如社交媒体垃圾机器人等)的支持。

        1. 如果你不付出足够的努力,来自云端IP范围的任何无头浏览器都将被互联网的大部分区域封禁。这不仅仅是关于垃圾邮件机器人,在许多情况下,你甚至无法阅读新闻文章。你将面临来自住宅代理和其他定制自动化解决方案的竞争,这些解决方案会为他们的客户处理所有这些问题。

          1. 谢谢,这确实如此!我们在过去构建Monitoro[0]和大型数据抓取管道时,就是通过这种方式学到的,因此我们有机会积累了必要的经验。

            需要注意的是,网站存在不同“层级”,每个层级都需要不同的应对措施。并非所有人都追求高竞争网站,而且最重要的是,我们从多个案例中了解到,抓取行为在某些情况下是完全获得用户同意或在用户权利范围内的。例如:

            * 许多用户抓取自己的网站以向Discord社区发送通知。这是一种无需编码即可创建警报的超级简单方式。

            * 有时用户被锁定在自己的服务提供商中,例如一些公司在其招聘管理系统(ATS)中积累了多年的职位发布信息,却无法提取。我们提供帮助解决此类问题。

            * 公共数据网站因数据难以获取而被低效利用。我们帮助将这些数据转化为可操作的信息。例如,一名水手通过设置浮标警报在高水位时确保安全。一个随机示例[1]

            0: https://monitoro.co

            1: https://wavenet.cefas.co.uk/details/312/EXT

    2. 我们在 metalsecurity.io 也有类似的解决方案 🙂 用于处理企业级用例的大规模自动化,绕过反机器人措施

      1. 这太棒了,感谢分享!不过这是基于Playwright的吧?你能确认你们采用的方法是否也受TFA漏洞影响吗?

        我最初的观点并非仅仅关于绕过反机器人保护,而是希望提供一种独立于现有解决方案(如 Puppeteer、Selenium 等)的浏览器自动化分支。我们认为这些工具并非为此目的设计,且如 TFA 所提到的,存在诸多限制,需要大量工作绕过,正如你的解决方案所示。

        1. 我们修复自动化框架的漏洞和问题,因此不存在此类问题。像您这样使用用户浏览器的方法,会因规模扩大而烧毁用户的指纹。

          1. 感谢分享您的经验!我对这个话题有强烈看法,请系好安全带 😀

            我们避免了分支与补丁的路线,因为这既耗时耗力且回报有限,还是一场追赶游戏。更新分支框架本身已具挑战性,更不用说将现有客户负载迁移到新版本,这会让你事实上被锁定在旧版本。我在前一家公司曾维护过一个与Browserless[0]规模相似的自定义分支,我可以告诉你那真是个噩梦。

            开发自己的框架(除了满足明显的 NIH 症候群)让你能够精确控制暴露范围(减少攻击面)从安全角度来看,并保护客户免受上游决策的影响,如弃用或重大更改,这些可能与客户需求不一致。我在这方面也有足够的经验,知道我们需要实现什么以及我们希望启用的功能。没有冗余(目前)

            > 根据规模,你会烧毁用户的指纹

            这取决于你的活动。参见我关于规模和用例的另一条评论,对于个人设备使用,这在实践中不是问题,用户可以使用他们的个人代理自动化多个网站[1]而无需担心这一点。对于更复杂的场景,我们有适当的策略来避免这个问题。

            > 我们修复自动化框架的泄露和漏洞

            听起来很有趣!我很乐意阅读相关文档,或查看您在上游项目中提交的PR。

            0: https://www.browserless.io/

            1: https://herd.garden/trails

            1. 听起来不错。想必您也深谙此道,我在这领域也有丰富经验 🙂 但公平地说,每个人对实现和维护的难易程度以及相关优缺点都有自己的看法。我们针对的是需要规模和速度的非常具体的用例,因此我们选择的路线最有意义。我显然不能分享我们的实现细节,因为这会暴露我们的规避措施。而这就是开源替代方案如 camoufox 和现已废弃的 puppeteer-stealth 的问题所在。

    3. 看来我们得想办法让这些机器人也崩溃。 😀

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: