反爬蟲中chrome無頭瀏覽器的幾種檢測與繞過方式
阿新 • • 發佈:2019-01-08
chrome無頭瀏覽器的幾種檢測方式
本文測試使用的chrome版本為 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3514.2 Safari/537.36
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.36
因此可以檢查UA中的關鍵字
if (/HeadlessChrome/.test(navigator.userAgent)) {
// headless...
}
2.Webdriver檢測
無頭模式下navigator.webdriver為true,因此可以進行如下檢測。
// Webdriver Test
if (navigator.webdriver) {
// headless...
}
為了繞過這個檢測,重新設定該屬性即可。
Object.defineProperty(navigator, 'webdriver', {
get : () => false,
});
3.chrome屬性檢測
在無頭模式下window.chrome屬性是undefined,而在正常有介面模式下,定義如下。
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(
因此可以進行如下形式檢測
if (!window.chrome || !window.chrome.runtime) {
// headless...
}
繞過檢測修改屬性即可
window.navigator.chrome = {
runtime: {},
// etc.
};
4.Permissions檢測
(async () => {
const permissionStatus = await navigator.permissions.query({ name: 'notifications' });
if(Notification.permission === 'denied' && permissionStatus.state === 'prompt') {
// headless
}
})();
無頭模式下Notification.permission與navigator.permissions.query會返回相反的值。
因此繞過的方式如下。
// Pass the Permissions Test.
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)
);
});
5. Plugins長度檢測
無頭模式下navigator.plugins.length返回0
if (navigator.plugins.length === 0) {
// headless
}
繞過方式如下
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
});
6.The Languages檢測
navigator.languages檢測方法
if (!navigator.languages || navigator.languages.length === 0) {
// headless
}
繞過方法
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en'],
});