1. 针对chromedriver的检测与绕过

1.1. UserAgent检测

无头模式下的UA会带有HeadlessChrome关键字,例如Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/70.0.3521.2 Safari/537.361,因此可以检查UA中的关键字。

1
2
3
4
if (/HeadlessChrome/.test(navigator.userAgent)) {
// headless...
}
//修改UserAgent即可绕过

1.2. Webdriver检测

无头模式下navigator.webdriver为true,因此可以进行如下检测。

1
2
3
4
5
6
7
8
// Webdriver Test
if (navigator.webdriver) {
// headless...
}
//重新设置该属性即可绕过
Object.defineProperty(navigator, 'webdriver', {
get: () => false,
});

但是说实话这个还是有点问题的,因为用”webdriver” in navigator还是能检测出来。

1.3. chrome属性检测

在无头模式下window.chrome属性是undefined,而在正常有界面模式下,定义如下。

1
2
3
4
5
6
7
8
9
10
11
12
csi: ƒ ()
embeddedSearch: {searchBox: {…}, newTabPage: {…}}
loadTimes: ƒ ()
app: (...)
runtime: (...)
webstore: (...)
get app: ƒ nativeGetter()
set app: ƒ nativeSetter()
get runtime: ƒ nativeGetter()
set runtime: ƒ nativeSetter()
get webstore: ƒ nativeGetter()
set webstore: ƒ nativeSetter()

因此可以进行如下形式检测。

1
2
3
4
5
6
7
8
if (!window.chrome || !window.chrome.runtime) {
// headless...
}
//修改属性即可绕过
window.navigator.chrome = {
runtime: {},
// etc.
};

1.4. Permissions检测

无头模式下Notification.permission与navigator.permissions.query会返回相反的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(async () => {
const permissionStatus = await navigator.permissions.query({ name: 'notifications' });
if(Notification.permission === 'denied' && permissionStatus.state === 'prompt') {
// headless
}
})();
//绕过方式如下
await page.evaluateOnNewDocument(() => {
const originalQuery = window.navigator.permissions.query;
return window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
});

1.5. Plugins长度检测

无头模式下navigator.plugins.length返回0。

1
2
3
4
5
6
7
if (navigator.plugins.length === 0) {
// headless
}
//绕过方式如下
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
});

1.6. The Languages检测

navigator.languages检测方法

1
2
3
4
5
6
7
if (!navigator.languages || navigator.languages.length === 0) {
// headless
}
//绕过方式如下
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en'],
});

2. 其它

2.1. span+css(限制窗口大小+背景图+图片偏移)+包含数字的SVG

出自大众点评网的人均和用户评论等信息,利用span标签配上css创建一个仅能容下一个数字的小窗口,将包含大量数字的SVG设置为背景,并通过调整图片相对于窗口的偏移来展示出相应的数字

  • 数字对应span标签

alt text

  • span标签对应的css,css的background-image为一张包含大量数字的SVG

alt text
绕过:获取CSS文件->获取SVG->分析SVG来获取坐标与数字的对照字典->根据span标签的class值定位到CSS->定位坐标->获取值

3. 验证码相关

3.1. Google验证码(ReCaptcha)

  • YesCaptcha
  • 2Captcha