selenium的檢測與突破


轉自: https://zhuanlan.zhihu.com/p/55956954

當使用selenium去某寶或其他網站進行爬蟲或者模擬登陸時,會出現滑動驗證碼,並且無論是用ActionChains滑還是手動滑,都會很委婉的告訴你“哎呀網絡錯誤,請刷新”等等。why?

經過科.xx學.xx上xx.網,查閱眾多資料,發現seleniumyou 有一些特征值, 例如下面:

window.navigator.webdriver
window.navigator.languages
window.navigator.plugins.length

其中最主要的特征值就是webdriver這一項。

partial interface Navigator {
      readonly attribute boolean webdriver;
  };

 

Navigator接口的webdriver IDL屬性必須返回webdriver-active標志的值,該標志默認值為false或者undefined。

此屬性允許網站確定用戶代理受WebDriver控制,並可用於幫助緩解壓力,拒絕服務攻擊。

直接取自2017 W3C Editor的WebDriver草案。這在很大程度上意味着,至少,未來selenium驅動程序迭代將被識別以防止濫用。

檢測方法:

檢查→Console→輸入"window.navigator.webdriver"

正常情況下為false或者undefined(根據瀏覽器穩定)

如果我們使用selenium自動化運行瀏覽器,然后在利用上述檢測方法,其值會是true

於是我開始摸索網站對於該特征值的檢測方法:

通過F12全局搜索,我發現在index.js中有webdriver的字段:

另外,還有兩個參數可以揭示使用了chromedriver:

1.“navigator.plugins.length”此參數可以檢測selenium的headless模式,headless模式下為0,所以可以添加假的值來規避檢測;

2.“navigator.languages”確保將此參數設置為chrome的默認值[“en-US”,“en”,"es"]

--------------------------------------------------------------------------------------------

ok,接下來我們要做的:

selenium被檢測的突破——修改webdriver的特征值

通過科,學,上,網,有一個方法是:

通過16進制編輯工具將chromedirver的$cdc_$wdc_這兩個變量名稱修改掉,但是我沒有嘗試,這里不做贅述,有興趣可自行嘗試。

我所使用的是利用mitmproxy通過代碼注入的方式進行修改webdriver的值。

'Object.defineProperties(navigator,{webdriver:{get:() => false}});' 

我們需要在index.js中的檢測webdriver前面注入一段代碼,將webdriver值改為替換為false。

1.為什么不使用selenium中的executeScript() 執行js代碼呢?

因為executeScript()是在網頁渲染完成后才執行。而檢測webdriver是在網頁渲染過程中檢測。所以無效。

2.手動在console修改webdriver值?

此方法治標不治本。只是臨時修改了webdriver值。並且,你需要在檢測瀏覽器指紋的XHR之前修改,才能有效。

-----------------------------------------------------------------------------------------------

總結:

1.網站通過“navigator.webdriver,navigator.languages,navigator.plugins.length”等參數瀏覽器指紋來檢測是否使用了selenium+webdriver。其中,之主要的特征為“webdriver”是否為true;

注意,在老版本的火狐瀏覽器會把webdriver直接用Attribute的形式寫入,因此可以使用檢測

window.document.documentElement.getAttribute(“webdriver”)

是否為true的方法,檢測是否使用了selenium。

2.修改chromedriver源碼;

3.使用mitmproxy或fiddler做代碼注入;

4.使用其他方法攔截發送回瀏覽器指紋的XHR

-----------------------------------------------------------------------------------------------

附一些網站檢測selenium的示例

runBotDetection = function () {
    var documentDetectionKeys = [
        "__webdriver_evaluate",
        "__selenium_evaluate",
        "__webdriver_script_function",
        "__webdriver_script_func",
        "__webdriver_script_fn",
        "__fxdriver_evaluate",
        "__driver_unwrapped",
        "__webdriver_unwrapped",
        "__driver_evaluate",
        "__selenium_unwrapped",
        "__fxdriver_unwrapped",
    ];

    var windowDetectionKeys = [
        "_phantom",
        "__nightmare",
        "_selenium",
        "callPhantom",
        "callSelenium",
        "_Selenium_IDE_Recorder",
    ];

    for (const windowDetectionKey in windowDetectionKeys) {
        const windowDetectionKeyValue = windowDetectionKeys[windowDetectionKey];
        if (window[windowDetectionKeyValue]) {
            return true;
        }
    };
    for (const documentDetectionKey in documentDetectionKeys) {
        const documentDetectionKeyValue = documentDetectionKeys[documentDetectionKey];
        if (window['document'][documentDetectionKeyValue]) {
            return true;
        }
    };

    for (const documentKey in window['document']) {
        if (documentKey.match(/\$[a-z]dc_/) && window['document'][documentKey]['cache_']) {
            return true;
        }
    }

    if (window['external'] && window['external'].toString() && (window['external'].toString()['indexOf']('Sequentum') != -1)) return true;

    if (window['document']['documentElement']['getAttribute']('selenium')) return true;
    if (window['document']['documentElement']['getAttribute']('webdriver')) return true;
    if (window['document']['documentElement']['getAttribute']('driver')) return true;

    return false;
};

 

try {
 if (window.document.documentElement.getAttribute("webdriver")) return !+[]
} catch (IDLMrxxel) {}
try {
 if ("_Selenium_IDE_Recorder" in window) return !+""
} catch (KknKsUayS) {}
try {
 if ("__webdriver_script_fn" in document) return !+""

 

改寫特征參數的js

// 改寫 `languages` 
Object.defineProperty(navigator, "languages", {
  get: function() {
    return ["en", "es"];
  }
});

//改寫 `plugins`
Object.defineProperty(navigator, "plugins", {
  get: () => new Array(Math.floor(Math.random() * 6) + 1),
});

// 改寫`webdriver`
Object.defineProperty(navigator, "webdriver", {
  get: () => false,
});


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM