I'm trying to develop a Firefox extension to protect user security by fighting against browser fingerprinting used for user tracking purposes.
Many, if not all fingerprinting techniques include recording contents of navigator.plugins, navigator.oscpu, navigator.platform, screen resolution, window toolbar height etc. Idea of an extension consists of two parts — first is to randomly filter and permutate plugins and their mime types, and induce randomness in other variables used for tracking; and second is to isolate webpage to prevent it from reusing previously hidden information — like .sol-cookies, utilizing fake E-Tags or anything not discovered yet.
Both methods require reimplementing getters on non-configurable properties of privileged navigator, screen, location objects, and this is the place where I'm stuck.
For example, following straightforward code being entered in Browser Console just does not work:
Object.defineProperty(getBrowser().contentWindow.location, 'href', {
get: function() {
return 'foobar';
}
});
It does not produce any errors, but does not redefine a property either. Moreover, it returns current value of location object for some reason — something that I don't expect from Object.defineProperty.
Replacing location with location.wrappedJSObject makes browser spit out TypeError: can't redefine non-configurable property 'href', identical to what non-privileged code will throw.
I tried to track down what happens when you call Object.defineProperty on something. It seems that it starts with js::obj_defineProperty(), then goes to js::StandardDefineProperty, which in turn does couple of checks, and descends to js::DefinePropertyOnObject, which has huge quantity of checks I don't fully understand yet, and finally ends with js::NativeDefineProperty, where the actual object modification is done.
So, questions are:
- Is it possible to redefine
location,navigator,screenobjects for a page content sandbox entirely, replacing them with some mocked proxies, controlled by my extension? - Or, is it possible to redefine non-configurable property of aforementioned objects?
- Or, is it possible to call
js::NativeDefinePropertyfrom chrome JavaScript? - Or (less preferred), is it possible to implement binary add-on to expose
js::NativeDefinePropertyto chrome as a service?
Update: I've got a question at Mozilla IRC, how is location rewriting related to privacy. Just for now all windows in private browsing mode share same cookies, storage and such, so you can still be tracked even in private mode, if you don't reset it too often. How often is too often is a question — ideally, you should reset after each visited site, because each site could mark you. It would be cool, if there was an ability to adjust granularity of private mode — like, separate private windows or tabs one from another.
I thought about tagging all URLs with some kind of tab-unique long random tag — so http://example.com/foo opened in two separate private tabs becomes http://example.com.AYZYXP/foo and http://example.com.QUSOFX/foo. From the browser's point of view, these are two distinct domain names, with their own caching rules, cookies, DOM storage, IndexedDB, FlashPlayer pesistence or anything else. From webpage's point of view it's necessary to keep the impression both tabs are http://example.com/foo, because exposing the tag will defy the idea of tagging — and that's why I need location rewriting.