反爬虫之检测 PhantomJS 访客,爬虫phantomjs,未经作者许可,禁止转载!


本文作者: 编橙之家 - 路易十四 。未经作者许可,禁止转载!
欢迎加入编橙之家 专栏作者。

翻译前言:作为数据采集工程师经常和反爬虫技术做斗争,其中我使用的爬虫结构是:分布式+多机器+adsl | tor+phantomjs无界面浏览器+机器学习验证码破解/这样的结构已经基本属于爬虫界的大招。但是对方如果通过检测 phantomjs 的浏览器特性还是能区别出爬虫。于是翻译本文知己知彼,翻译功底不好切勿见怪,高手请移步文尾部可以看英语原文。

这些天,许多web安全事故涉及自动化。 Web-scraping、密码重用和点击欺诈攻击对手试图模拟真实用户,从而将请求看起来像是来自一个浏览器。作为网站的所有者,你想确保你的web是为人类服务。假设你有基本的检查cURL-like访客的能力,下一个合理的步骤是确保访客使用的是真正的ui驱动浏览器——而不是无头浏览器 PhantomJS SlimerJS 在本文中,我们将展示一些PhantomJS检测的技术。 我们决定专注于PhantomJS因为它是最受欢迎的无头浏览器环境,但许多的概念,我们将讨论适用于SlimerJS和其他工具。

目录:

  1. HTTP栈
  2. 客户端User-Agent  检查
  3. 使用插件
  4. 定时
  5. 全局属性
  6. 缺乏JavaScript引擎的功能
  7. 堆栈跟踪

 

1: 检查HTTP栈

首先:它可以检测PhantomJS甚至在不用相应他(在获取请求头就可以检测他)吗?

如你所知,PhantomJS是建立在 Qt框架 。 Qt实现HTTP栈的方式使它突出于其他现代浏览器。

首先,让我们看看Chrome,发出以下head:

JavaScript
GET / HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6

然而在PhantomJS,相同的HTTP请求是这样的:

Python
GET / HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.8 Safari/534.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: Keep-Alive
Accept-Encoding: gzip
Accept-Language: en-US,*
Host: localhost:1337

你会注意到PhantomJS头是不同于Chrome(事实证明,其他所有现代浏览器)有一些微妙的不同:

  • 主机(host) 出现最后一行
  • 连接头(Connection)是大小写混合
  • 唯一的 接受编码 值是gzip
  • User-Agent 包含“PhantomJS”

在服务器上检查这些HTTP头的变化,它应该可以识别PhantomJS浏览器。

但是,相信这些值安全吗? 如果敌人使用一个代理修改标题前面的无头浏览器,他们可以修改这些标题显得象一个正常的现代浏览器。

看来解决这个问题纯粹只是在服务器上不是合适的。 让我们看看能做些什么在客户端,现在使用PhantomJS的JavaScript环境。

 

2: 客户端User-Agent  检查

我们可能无法通过HTTP信任User-Agent 的值但是在客户端呢?

Python
if (/PhantomJS/.test(window.navigator.userAgent)) {
    console.log("PhantomJS environment detected.");
}

不幸的是,它同样是可以被改变User-Agen和head 在PhantomJS 中检测userAgent值,这可能是不够的。

 

3: 使用插件

navigator.plugins 包含一个数组的插件在浏览器内。 典型的插件的价值观包括Flash,ActiveX,支持Java applet,“ 默认浏览器助手 ”,这是一个插件,表明这个浏览器是OS x的默认浏览器是否在我们的研究中,大多数新安装的常见的浏览器包括至少一个默认插件。

这是与PhantomJS,不实现任何插件,也不提供一种方法来添加一个(使用 PhantomJS API )。

以下检查可能会是有用的:

Python
if (!(navigator.plugins instanceof PluginArray) || navigator.plugins.length == 0) {
    console.log("PhantomJS environment detected.");
} else {
    console.log("PhantomJS environment not detected.");
}

另一方面,恶搞这个插件很简单数组通过修改PhantomJS JavaScript环境 在页面加载之前

也不难想象一个自定义构建的PhantomJS真实,实现插件。 这比听起来要容易得多,因为Qt PhantomJS构建提供了一个框架 本机API 实现插件。

 

4: 定时

另一个感兴趣的点是如何PhantomJS抑制JavaScript对话框:

Python
var start = Date.now();
alert('Press OK');
var elapse = Date.now() - start;
if (elapse < 15) {
    console.log("PhantomJS environment detected. #1");
} else {
    console.log("PhantomJS environment not detected.");
}

多次测量后,似乎如果警告对话框被限制了在15毫秒,浏览器可能不是被一个真实的人控制。 但使用这种方法意味着困扰真实用户与一个警告他们会手动关闭。

 

5: 全局属性

PhantomJS 1。 x暴露在全局对象两个属性:

Python
if (window.callPhantom || window._phantom) {
  console.log("PhantomJS environment detected.");
} else {
  console.log("PhantomJS environment not detected.");
}

然而,这些属性的一部分 实验功能 和在未来可能会改变。

 

6: 缺乏JavaScript引擎的功能

PhantomJS 1. x和2. x目前使用过时的WebKit引擎,这意味着有浏览器特性中存在的新浏览器PhantomJS并不存在。 这延伸到JavaScript引擎——即一些本机属性和方法是不同的或在PhantomJS缺席。其中一个方法是Function.prototype。 绑定,PhantomJS 下面的示例检查是否存在绑定,它没有被欺骗的执行环境。

Python
(function () {
  if (!Function.prototype.bind) {
    console.log("PhantomJS environment detected. #1");
    return;
  }
  if (Function.prototype.bind.toString().replace(/bind/g, 'Error') != Error.toString()) {
    console.log("PhantomJS environment detected. #2");
    return;
  }
  if (Function.prototype.toString.toString().replace(/toString/g, 'Error') != Error.toString()) {
    console.log("PhantomJS environment detected. #3");
    return;
  }
  console.log("PhantomJS environment not detected.");
})();

这段代码是有点太棘手的详细解释,但你可以找到更多 我们的演示

 

7: 堆栈跟踪

错误抛出的JavaScript代码由PhantomJS通过评估 评估 命令包含一个堆栈跟踪的唯一标识,我们可以确定无头浏览器。

例如,假设PhantomJS评估以下代码:

Python
var err;
try {
  null[0]();
} catch (e) {
  err = e;
}
if (indexOfString(err.stack, 'phantomjs') > -1) {
  console.log("PhantomJS environment detected.");
} else {
  console.log("PhantomJS environment is not detected.");
}

注意,这个示例使用一个定制的 indexOfString() 函数,留给读者作为练习,因为本机String.prototype.indexOf 可以欺骗PhantomJS总是返回一个负面的结果。

现在,你如何让PhantomJS脚本运行这段代码? 技术之一是覆盖一些经常使用DOM API函数可能被称为。 例如,下面的代码覆盖 document.querySelectorAll 检查浏览器的堆栈跟踪:

Python
var html = document.querySelectorAll('html');
var oldQSA = document.querySelectorAll;
Document.prototype.querySelectorAll = Element.prototype.querySelectorAll = function () {
  var err;
  try {
    null[0]();
  } catch (e) {
    err = e;
  }
  if (indexOfString(err.stack, 'phantomjs') > -1) {
    return html;
  } else {
    return oldQSA.apply(this, arguments);
  }
};

总结

在本文中,我们研究了7个不同的技术来识别PhantomJS,都在服务器上,执行代码PhantomJS的客户端JavaScript环境。 结合检测结果与一个强大的反馈机制——例如,呈现动态页面惰性或无效当前会话cookie——你可以获得一个坚实的阻止PhantomJS访客的防火墙。 然而,总是记住这些技术并不可靠,和一个复杂的对手最终将获得通过。

为了了解更多,我们建议看的记录 从2014年美国AppSec我们的演示 ( 幻灯片 )。 我们也放在一起 GitHub库 实现示例和可能的危害,本文提供的技术。

感谢你的阅读,快乐狩猎。

贡献者:

  • Sergey Shekyan – @sshekyan
  • Ben Vinegar – @bentlegen
  • Bei Zhang – @ikarienator
  • 链接分享:

英文原文    翻译文: GitHub库

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

评论关闭