admin管理员组

文章数量:1202791

I am trying to overload the navigator.userAgent using a simple chrome extension. As the content scripts operate in isolated env, I tried to create a script element and write the logic into this one. This happens from background page of the extension

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
      });
    }
  });

The script gets appended for the head element and I can see that the UA string as the one that is spoofed by trying navigator.userAgent in the console of the chrome and so I believe that the navigator object was overloaded.

But this seems to be not the effective way or not happening at all as the navigator object was not updated which I found out via - .html which still shows the UA for Mac.

So, what exactly am I missing here?

I am trying to overload the navigator.userAgent using a simple chrome extension. As the content scripts operate in isolated env, I tried to create a script element and write the logic into this one. This happens from background page of the extension

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
      });
    }
  });

The script gets appended for the head element and I can see that the UA string as the one that is spoofed by trying navigator.userAgent in the console of the chrome and so I believe that the navigator object was overloaded.

But this seems to be not the effective way or not happening at all as the navigator object was not updated which I found out via - http://www.quirksmode.org/js/detect.html which still shows the UA for Mac.

So, what exactly am I missing here?

Share Improve this question asked Apr 21, 2014 at 17:13 Srikanth RayabhagiSrikanth Rayabhagi 1,4433 gold badges13 silver badges24 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 17

navigator.userAgent is a read-only property. If you want to change navigator.userAgent, then you need to either create a new object and copy the properties, or create a new object and inherit from navigator and assign a new getter/setter.

I've recently created such an extension. I'm on Linux, though I occasionally download the Chrome for Windows. The following extension changes the user agent to Windows XP on Chrome's download page:

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/*"
        ]
    }]
}

As you can see, I'm declaring the content script instead of dynamically inserting it, to make sure that my code runs before the page is loaded. Further, I'm using one of the tricks described in this answer to change the page's navigator instead of some other navigator in the isolated content script world.

Note that this only modifies the userAgent as seen from JavaScript. If you want to modify the user agent that's sent to the server, take a look at Associate a custom user agent to a specific Google Chrome page/tab.

#Rob W,Thanks!

Cool! But the site crashes if some navigator values are accessed. Therefore, it would be better to completely recreate the navigator.

function setupUserAgentHook(UserAgent){
if(typeof UserAgent !== 'string' && UserAgent == '')
    return false;
    function addslashes(str) { // Quote string with slashes
    return str.replace(/([\"\'])/g, "\\$1");
}
var actualCode = '(' + function(newUserAgent){
    'use strict';
    
    var navigator = Object.create(window.navigator);
    function rTMPL(o){
        return {
            value: o,
            configurable: false,
            enumerable: true,
            writable: false
        }
    }
    var ChromeV = newUserAgent.replace(/^.*Chrome\/(\d+).*$/gi,'$1');

    Object.defineProperties(navigator, {
        userAgent: rTMPL(newUserAgent),
        appVersion: rTMPL(newUserAgent),
        platform: rTMPL('Win32'),
        productSub: rTMPL('20030107'),
        language: rTMPL('en-US'),
        languages: rTMPL(['en-US', 'en']),
        userAgentData: rTMPL({"brands":[{"brand":" Not A;Brand","version":ChromeV},{"brand":"Chromium","version":ChromeV},{"brand":"Google Chrome","version":ChromeV}],"mobile":false}),

        deviceMemory: rTMPL(8), 
        hardwareConcurrency: rTMPL(8),

        maxTouchPoints: rTMPL(0),msMaxTouchPoints: rTMPL(0),
        vendor: rTMPL('Google Inc.'),appCodeName: rTMPL('Mozilla'),appName: rTMPL('Netscape'),product: rTMPL('Gecko'),
        bluetooth: rTMPL({}),clipboard: rTMPL({}),credentials: rTMPL({}),ink: rTMPL({}),keyboard: rTMPL({}),locks: rTMPL({}),mediaCapabilities: rTMPL({}),permissions: rTMPL({}),plugins: rTMPL({}),
        scheduling: rTMPL({}),storage: rTMPL({}),wakeLock: rTMPL({}),webkitPersistentStorage: rTMPL({}),webkitTemporaryStorage: rTMPL({}),windowControlsOverlay: rTMPL({}),
        onLine: rTMPL(true),pdfViewerEnabled: rTMPL(true),cookieEnabled: rTMPL(true),webdriver: rTMPL(false),doNotTrack: rTMPL(null),vendorSub: rTMPL(""),xr: rTMPL("XRSy"),

        mediaDevices: rTMPL({ondevicechange: null}),
        usb: rTMPL({onconnect: null, ondisconnect: null}),
        hid: rTMPL({onconnect: null, ondisconnect: null}),
        managed: rTMPL({onmanagedconfigurationchange: null}),
        serial: rTMPL({onconnect: null, ondisconnect: null}),
        presentation: rTMPL({defaultRequest: null, receiver: null}),
        mediaSession: rTMPL({metadata: null, playbackState: 'none'}),
        userActivation: rTMPL({hasBeenActive: true, isActive: true}),
        virtualKeyboard: rTMPL({boundingRect: DOMRect, overlaysContent: false, ongeometrychange: null}),
        connection: rTMPL({"downlink":10,"effectiveType":"4g","onchange":null,"rtt":50,"saveData":false}),
        serial: rTMPL({controller: null, ready: Promise, oncontrollerchange: null, onmessage: null, onmessageerror: null}),
        geolocation: rTMPL({getCurrentPosition: function(fs,fe,o){fe({code: 1, message: 'User denied Geolocation'})}, watchPosition: function(fs,fe,o){fe({code: 1, message: 'User denied Geolocation'})}}),
        mimeTypes: rTMPL({0: 'MimeType', 1: 'MimeType', 2: 'MimeType', 3: 'MimeType', 'application/pdf': 'MimeType', 'application/x-google-chrome-pdf': 'MimeType', 'application/x-nacl': 'MimeType', 'application/x-pnacl': 'MimeType', 'length': 4})
    });
    Object.defineProperty(window, 'navigator', {
        value: navigator,
        configurable: true,
        enumerable: true,
        writable: true
    });             
} + ')("'+addslashes(UserAgent)+'");';

document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');
}
setupUserAgentHook('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36');

Are you trying to change the User-Agent header that gets sent in requests? You'll have to use the declarativeWebRequest or webRequest APIs.

Running content scripts in the page only occurs after the requests have been sent.

本文标签: javascriptChanging navigatoruserAgent using Chrome ExtensionStack Overflow