可靠地检测基于PhantomJS的垃圾邮件机器人

24

有没有一种可以稳定地检测PhantomJS/CasperJS的方法?我一直在处理用它构建的恶意垃圾机器人,并且已经能够基于某些行为大部分地封锁它们,但是我很想知道是否有一种可靠的方法来确定是否使用了CasperJS,因为不断适应变得有点烦人。

我不相信使用验证码。它们会给用户带来负面体验,而且ReCaptcha从未成功阻止我在MediaWiki安装中的垃圾邮件。由于我们的网站没有用户注册(匿名讨论板),所以我们需要对每篇文章都进行验证码输入。我们每天会收到数千篇合法文章,而验证码会使这个数字骤降。


你尝试过QuestyCaptcha吗?它可以让你选择一组静态问题。除非你的网站特别受到垃圾邮件机器人的攻击,否则这对于机器人来说几乎是无法克服的,对于人类来说则非常容易。 - Nemo
3个回答

22

我非常赞同您对CAPTCHA的看法。我将列出迄今为止我已经能够检测到的内容,供我的检测脚本使用,其目标类似。这只是部分内容,因为有许多其他无头浏览器

可以相对安全地使用公开的窗口属性来检测/假设那些特定的无头浏览器:

window._phantom (or window.callPhantom) //phantomjs
window.__phantomas //PhantomJS-based web perf metrics + monitoring tool 
window.Buffer //nodejs
window.emit //couchjs
window.spawn  //rhino

上述内容摘自jslint文档和使用Phantom JS进行测试。

浏览器自动化驱动程序(由BrowserStack或其他网络捕获服务用于快照):

window.webdriver //selenium
window.domAutomation (or window.domAutomationController) //chromium based automation driver

这些属性并不总是暴露出来的,我正在研究其他更为稳健的方法来检测这样的机器人,当完成时我可能会发布一个完整的脚本。但这主要回答了你的问题。

这里有另一种相当可靠的方法可以更广泛地检测支持JS的无头浏览器:

if (window.outerWidth === 0 && window.outerHeight === 0){ //headless browser }

这应该能够很好地工作,因为即使无头浏览器设置了虚拟视口大小,属性默认也是0,在默认情况下它不能报告不存在的浏览器窗口的大小。特别是,Phantom JS 不支持outerWidth或outerHeight

补充说明:然而,Chrome/Blink存在outer/innerDimensions的一个bug。当一个页面在隐藏选项卡中加载时,例如从上一个会话中恢复时,Chromium 不会报告这些维度Safari似乎没有这个问题。

更新:事实证明iOS Safari 8+存在outerWidth和outerHeight为0的错误,Sailfish webview也可能存在这个问题。因此,尽管它是一种信号,但如果不考虑这些错误,它不能单独使用。因此,警告:除非您确切知道自己在做什么,请不要使用此原始代码。

PS:如果您知道这里未列出的其他无头浏览器属性,请在评论中分享。


3
在我调查的情况下, navigator.onLine 属性的值是 FALSE (PhantomJS 也是如此)。我测试过的常规浏览器都返回了 onLine 的 TRUE 值。 - PeterK
1
此外,我的情况下navigator.plugins为空,这也与PhantomJS一致。 - PeterK
无论如何,我认为任何合理的具有未来性的检测方法都应该针对那些不容易伪造的属性。更改JS公开的对象名称,提供一个令人信服的window.outer*属性对,将navigator.onLine设置为TRUE甚至提供插件列表对于有恶意意图的人来说都非常容易。我可以想到一些方法,比如检测键盘/鼠标/触摸交互(相对容易被击败),或者指纹识别浏览器功能(应该很难被击败)。 - PeterK
我在考虑编制一个已知的特定于桌面浏览器的User-Agent模式列表。当然,这是基于移动浏览器使用可区分于其桌面对应物的User-Agent字符串的假设。即使如此,我只会建议将此度量标准用于多个属性的启发式模型中。 - PeterK
1
@PeterK 不,它们是无法区分的。而且我已经在生产环境中使用一个 JS 脚本来完全检测移动设备上伪装成“桌面模式”的代理程序。但这个主题超出了这个问题的范围。 - hexalys
显示剩余3条评论

3

您可以通过检查window.callPhantom属性在客户端上检测幽灵进程。在客户端上的最小脚本如下:

var isPhantom = !!window.callPhantom;

这里有一个示例,证明这个方法是行得通的。

垃圾邮件发送者可以使用page.evaluate删除此属性,然后取决于谁更快。在检测后,您需要使用帖子表单重新加载页面,并根据您的检测结果添加或不添加CAPTCHA。

问题是这会产生一个可能会使用户烦恼的重定向。这对客户端上的每种检测技术都是必需的。但可以通过onResourceRequested进行规避和更改。

一般来说,我认为这是不可能的,因为你只能在客户端上进行检测并将结果发送到服务器。仅使用一个页面加载步骤添加CAPTCHA并结合检测步骤并没有真正增加任何东西,因为它可以像phantomjs/casperjs一样轻松地移除。基于用户代理的防御也没有意义,因为它在phantomjs/casperjs中可以很容易地更改。


page没有暴露给窗口。这是一个内部的phantomjs属性,用于请求实际页面。问题是在使用phantomjs执行页面时,如何从js窗口范围内检测到phantom。 - hexalys
这只是为了说明工作探测器的原理。如果它似乎令人困惑,我会简化代码。 - Artjom B.

3
没有绝对可靠的方法:PhantomJS和Selenium只是用于控制浏览器软件的软件,而不是用户控制它。
特别是在PhantomJS 1.x中,我认为有一些JavaScript可以利用正在使用的WebKit版本中的漏洞来使浏览器崩溃(它相当于Chrome 13,因此很少有真正的用户会受到影响)。 (我记得几个月前在幽灵邮件列表中提到过这一点,但我不知道是否描述了要使用的确切JS。)更一般地,您可以使用用户代理匹配与功能检测相结合。例如,如果浏览器声称是“Chrome 23”,但没有Chrome 23具有的功能(而Chrome 13没有),则应该引起怀疑。
作为用户,我也讨厌验证码。但是它们非常有效,因为它们增加了垃圾邮件发送者的成本:他必须编写更多的软件或雇用人员来阅读它们。(这就是为什么我认为易于识别的CAPTCHA已经足够好了:那些让用户感到恼火的是你根本不知道它在说什么,必须不停地刷新才能获得你认识的东西。)
一种方法(我认为Google正在使用)是条件地显示CAPTCHA。例如,已登录的用户永远不会看到它。本次会话中已经发布过一篇文章的用户不会再次看到它。来自白名单中的IP地址的用户不会看到它们。或者相反,只向黑名单中的IP范围内的用户显示它们。
我知道这些方法都不完美,很抱歉。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接