• selenium的检测与突破


    转载: https://zhuanlan.zhihu.com/p/56040461


    当使用selenium去某宝或其他网站进行爬虫或者模拟登陆时,会出现滑动验证码,并且无论是用ActionChains滑还是手动滑,都会很委婉的告诉你“哎呀网络错误,请刷新”等等。why?

    经过科学上网,查阅众多资料,发现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(根据浏览器稳定)

    在这里插入图片描述
    于是我开始摸索网站对于该特征值的检测方法:

    通过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的cdccdc_和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,
    });
    

    再次声明:
    本文转载自:selenium的检测与突破 https://zhuanlan.zhihu.com/p/55956954

  • 相关阅读:
    Java匹马行天下之JavaSE核心技术——工具类
    微信小程序
    在express3里用ejs模版引擎时,如何使其支持'.html'后缀
    node
    webstorm常用快捷键
    Meta标签中的format-detection属性及含义
    使用console进行 性能测试 和 计算代码运行时间
    JS获取浏览器URL中查询字符串的参数
    jspm 简介
    vue2.0 keep-alive最佳实践
  • 原文地址:https://www.cnblogs.com/onefine/p/10499325.html
Copyright © 2020-2023  润新知