【问题标题】:Changing navigator.userAgent using Chrome Extension使用 Chrome 扩展更改 navigator.userAgent
【发布时间】:2014-06-05 19:08:21
【问题描述】:

我正在尝试使用简单的 chrome 扩展来重载 navigator.userAgent。由于内容脚本在隔离环境中运行,我尝试创建一个脚本元素并将逻辑写入此元素。这发生在扩展的背景页面

chrome.tabs.query({
  active:!0
}, function(tabs) {
    var x = "window.navigator.__defineGetter__('userAgent', function() {" +
            "return 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D)" +
            " AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile " + 
            "Safari/535.19'; });console.log(navigator.userAgent);";

    for (var i = 0;i < tabs.length;i++) {
      var code = 'var s = document.createElement("script"); s.text = "' + x +
                 '"; document.head.insertBefore(s, document.head.firstChild);' + 
                 'navigator.userAgent ="s"; console.log(navigator.userAgent);';

      // Inject into the tabs of choice - currently everything.
      chrome.tabs.executeScript(tabs[i].id, {
        code: code
      });
    }
  });

脚本为 head 元素附加,我可以看到 UA 字符串是通过在 chrome 控制台中尝试 navigator.userAgent 来欺骗的字符串,因此我认为 navigator 对象已重载。

但这似乎不是有效的方法,或者根本没有发生,因为导航器对象没有更新,我通过 http://www.quirksmode.org/js/detect.html 发现它仍然显示 Mac 的 UA。

那么,我到底错过了什么?

【问题讨论】:

    标签: javascript html google-chrome google-chrome-extension


    【解决方案1】:

    您是否尝试更改在请求中发送的 User-Agent 标头?您必须使用 declarativeWebRequest 或 webRequest API。

    仅在请求发送后才会在页面中运行内容脚本。

    【讨论】:

    • 是的,我正在使用 chrome.webRequest API 来修改标头中的 UserAgent ,但这仍然不足以更新 navigator.userAgent 。所以,我试图在它发送请求标头时覆盖 userAgent。
    【解决方案2】:

    navigator.userAgent 是只读属性。如果要更改navigator.userAgent,则需要创建一个新对象并复制属性,或者创建一个新对象并从navigator 继承并分配一个新的getter/setter。

    我最近创建了这样一个扩展。我在 Linux 上,但我偶尔会下载适用于 Windows 的 Chrome。以下扩展在 Chrome 的下载页面上将用户代理更改为 Windows XP:

    contentscript.js

    var actualCode =  '(' + function() {
        'use strict';
        var navigator = window.navigator;
        var modifiedNavigator;
        if ('userAgent' in Navigator.prototype) {
            // Chrome 43+ moved all properties from navigator to the prototype,
            // so we have to modify the prototype instead of navigator.
            modifiedNavigator = Navigator.prototype;
    
        } else {
            // Chrome 42- defined the property on navigator.
            modifiedNavigator = Object.create(navigator);
            Object.defineProperty(window, 'navigator', {
                value: modifiedNavigator,
                configurable: false,
                enumerable: false,
                writable: false
            });
        }
        // Pretend to be Windows XP
        Object.defineProperties(modifiedNavigator, {
            userAgent: {
                value: navigator.userAgent.replace(/\([^)]+\)/, 'Windows NT 5.1'),
                configurable: false,
                enumerable: true,
                writable: false
            },
            appVersion: {
                value: navigator.appVersion.replace(/\([^)]+\)/, 'Windows NT 5.1'),
                configurable: false,
                enumerable: true,
                writable: false
            },
            platform: {
                value: 'Win32',
                configurable: false,
                enumerable: true,
                writable: false
            },
        });
    } + ')();';
    
    var s = document.createElement('script');
    s.textContent = actualCode;
    document.documentElement.appendChild(s);
    s.remove();
    

    manifest.json

    {
        "name": "navigator.userAgent",
        "description": "Change navigator.userAgent to Windows on Chrome's download page.",
        "version": "1",
        "manifest_version": 2,
        "content_scripts": [{
            "run_at": "document_start",
            "js": ["contentscript.js"],
            "matches": [
                "*://www.google.com/intl/*/chrome/browser/*"
            ]
        }]
    }
    

    如您所见,我是declaring the content script,而不是动态插入它,以确保我的代码在页面加载之前运行。此外,我正在使用described in this answer 中的一种技巧来更改页面的navigator,而不是在孤立的内容脚本世界中更改其他一些navigator

    请注意,这只会修改从 JavaScript 中看到的 userAgent。如果您想修改发送到服务器的用户代理,请查看Associate a custom user agent to a specific Google Chrome page/tab

    【讨论】:

    • 这个方法我是一周前想出来的,忘记在这里更新了。但是您的解决方案与 navigator 的其他属性很优雅,这可能有助于我进行完美的仿真。我仍然留下的一个问题是,如果我在注入脚本之前使用 chrome 消息传递来确认背景页面的某些内容,那么脚本的注入速度会很慢,在某些情况下,内联脚本会在消息传递完成之前执行。有解决办法吗?
    • @SrikanthRayabhagi 我在crbug.com/334486 列出了一些解决方法。这些都是 hack,您应该只将它们视为最后的手段。
    • 我在“userAgent: {”行收到非法调用错误。知道那可能是什么吗?我所做的唯一更改是引用了整个内容,而不是让函数不在引号中。
    • @RyanAmos Chrome 43 改变了内置对象的定义方式。我更新了答案,再试一次。
    • 查看gist.github.com/thorsten/148812e9cc4fb6a19215ce22afd4e5a8 了解也适用于其他浏览器的代码。
    猜你喜欢
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    相关资源
    最近更新 更多