原文:Detecting Chrome Headless
作者:Antoine Vastel
作者注:我在Github上建了一个可以利用浏览器指纹来检测机器人和爬虫的库,虽然仍在开发中,但各位看官已经可以开始使用了,飞机票在此。
何为无头浏览器
无头浏览器(Headless browser)是一种无需图形操作界面的浏览器。可以被程序所控制,执行自动化程序,比如进行测试和对网页截图。
为何要检测无头浏览器
除了以上所提到的两个无公害的例子,无头浏览器还可以自动化执行恶意任务。最常见情况的是爬取网页信息,刷广告展示量和寻找网站漏洞。
目前,PhantomJS是最受欢迎的无头浏览器之一,而由于它是基于 Qt 框架所构建,所以和主流的浏览器相比,存在很多不同之处。如此文所示,我们可以通过一些浏览器指纹技术来检测到它。
从Chrome的第59版开始,谷歌发布了一个无头版本Chrome浏览器。不同于PhantomJS,它的开发是基于Vanilla版的Chrome,而不是外部框架,这就导致
它更加难以被检测到。
接下来,我们将介绍几种可以用于区分普通Chrome和无头Chrome的技术。
如何检测无头Chrome浏览器
作者注:我们仅仅在两台Linux和两台Mac上做过测试,所以可能还有其它的方法可以检测无头Chrome浏览器。
1. 通过User Agent信息检测
我们从User Agent开始,它是一个检测操作系统和浏览器的常用属性。在Linux下,使用无头Chrome浏览器,User Agent的值为:“Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/59.0.3071.115 Safari/537.36”
因此,我们可以用以下代码检测到它:
if (/HeadlessChrome/.test(window.navigator.userAgent)) {
console.log("Chrome headless detected");
}
HTTP请求头也包含有User Agent信息,但是这两种方式获取到的User Agent都很容易进行伪装。
2. 通过浏览器插件信息检测
navigator.plugins可以返回一个包含浏览器插件信息的数组。一般来说,在正常的Chrome上,可以找到一些默认插件,比如 Chrome PDF viewer或者 Google Native Client。而在无头模式下,这个返回的数组没有任何插件信息。
if(navigator.plugins.length == 0) {
console.log("It may be Chrome headless");
}
3.通过浏览器的语言信息检测
在Chrome中Javascript有两个属性可以获取到用户使用的语言:navigator.language 和 navigator.languages。前者返回浏览器的界面语言,后者返回一个包含用户的首选语言的字符串数组,而在无头模式下,navigator.languages 返回的是空字符串。
if(navigator.languages == "") {
console.log("Chrome headless detected");
}
4.通过WebGL查看图形驱动信息检测
WebGL是一个在HTML canvas中执行3D渲染的API,它可以查询到图形驱动的渲染器和发布者。
在Linux环境下,我利用Chrome正常模式获得的渲染器和发布者分别为:“Google SwiftShader” 和 “Google Inc”。而在无头模式下,我获得的是 “Mesa OffScreen” 和 “Brian Paul”,前者是不对任何窗口进行渲染的技术,后者是开发了 Mesa 开源图形库 的组织。
var canvas = document.createElement('canvas');
var gl = canvas.getContext('webgl');
var debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
if(vendor == "Brian Paul" && renderer == "Mesa OffScreen") {
console.log("Chrome headless detected");
}
然鹅,并不是所有的无头Chrome都能得到相同的发布者和渲染器信息,有的会带有正常浏览器版本的相关信息。但是,“Mesa OffScreen” 和 “Brian Paul” 代表的一定是无头模式。
5.通过浏览器的Hairline功能检测
Modernizr 库可以测试浏览器中是否能展示 HTML 和 CSS 样式。我们在 Chrome 和 无头Chrome 之间目前只找到了一个区别,就是后者不支持 Hairline 功能,所以我们可以通过此功能的有无进行检测。
if(!Modernizr["hairline"]) {
console.log("It may be Chrome headless");
}
6.通过加载失败的图片情况检测
我们最后也是最强有力的发现,是来自 Chrome 对于无法加载的图片的尺寸处理。
在正常模式下,加载失败的图片的大小取决于浏览器的缩放情况,但绝不会等于零。而在无头模式下,此类图片的宽高都等于零。
var body = document.getElementsByTagName("body")[0];
var image = document.createElement("img");
image.src = "http://iloveponeydotcom32188.jg";
image.setAttribute("id", "fakeimage");
body.appendChild(image);
image.onerror = function(){
if(image.width == 0 && image.height == 0) {
console.log("Chrome headless detected");
}
}