Opened 4 years ago

Closed 4 years ago

Last modified 3 years ago

#1816 closed task (fixed)

Create a prototype Content Script for Google Chrome

Reported by: mikeperry Owned by: mikeperry
Priority: normal Milestone:
Component: Torbutton Version:
Keywords: Cc:
Actual Points: Parent ID: #1770
Points:

Description

We should check to see if Google Chrome's content scripts are robust enough for us to hook the javascript components we need to hook to mitigate fingerprinting and other Torbutton-related issues. The Chrome people offered to fix shortcomings if we can provide them with test cases sooner rather than later.

Child Tickets

Attachments (3)

TorMode.crx (6.1 KB) - added by mikeperry 4 years ago.
Apply content scripts to iframes. Update version to 0.0.4
TorMode-0.0.5.crx (6.1 KB) - added by mikeperry 4 years ago.
Document scoping and potential issues.
TorMode-0.0.6.crx (6.8 KB) - added by mikeperry 4 years ago.
Clean up code+comments a bit more.

Download all attachments as: .zip

Change History (18)

comment:1 Changed 4 years ago by mikeperry

Damn. Just a few minutes into this and it quickly becomes apparent that we cannot use Content Scripts to do what we want. My plan was to use content scripts in Google chrome to implement Torbutton's fingerprinting protection mechanisms, and to also work on a prototype general anti-fingerprinting addon to counter many of these issues and to light a fire under Mozilla to give us the APIs we need: https://wiki.mozilla.org/Fingerprinting

The problem is that it appears pretty clear that at least currently, there is no way for content scripts to do anything other than DOM manipulation, which does *not* include objects that can be found off of window, such as window.Date, window.plugins, window.navigator, and window.screen - all of which are crucial to wrap to provide fingerprint resistance.

The core problem is that these objects are sandboxed and shadowed by the Chrome "isolated worlds" concept: https://code.google.com/chrome/extensions/content_scripts.html#execution-environment

This may mean that it is not possible to use content scripts to provide either Torbutton for Chrome protections, or to provide an anti-fingerprinting addon for Chrome, at least for the short term, or until new APIs are provided.

comment:2 Changed 4 years ago by mikeperry

Perhaps all is not yet lost. My brother pointed out that I can use a content script to insert a <script> tag into the DOM with fixed script text that may do what I want, because it should execute in the actual content window's javascript vm. I will try this today.

comment:3 Changed 4 years ago by mikeperry

Alright! Thanks to some more help from my brother, I've got this working. We can't use a script.src url directly, because then Chrome delays the load until it starts loading other page elements. However, we can stuff the thing into a function closure and then use .toString() to shove that into script.innerHTML.

The prototype I have cloaks timezone, resolution, and javascript-available user agent and plugin information. It has a few issues:

  1. It's not clear if the script.innerHTML trick is just allowing us to win a race, or if we are actually assured to run before all page script because we use "run_at": "document_start" in our manifest.
  1. It's not clear if we've covered enough protocols in our permissions section of the manifest, especially if Javascript can register custom protocol handlers like it can in Firefox.
  1. We cannot actually yet actively request that the addon be run in Incognito mode. The user has to manually tick a checkbox before it does anything at all (because it only works in Incognito mode).
  1. It's not clear if we successfully defeat all the anti-js-rootkit stuff that Greg Fleischer did against Torbutton a few years back. All his tests do fail out of the box, though.
  1. There are still other issues that remain with a proper Tor mode, most notably:
    1. Incognito specific proxy settings that are DNS-leak safe.
    2. Preventing plugins from loading, or otherwise muzzling/sandboxing them
    3. Blocking versions of the WebRequest APIs.
    4. Preventing external apps from being launched without a proper warning
    5. Odd bits of SSL state and other things that may still persist in Incognito mode

comment:4 Changed 4 years ago by mikeperry

  • Resolution set to fixed
  • Status changed from new to closed

To install this prototype in Chrome from this bugtracker, click on the attachment, go to download, and then allow Chrome to install it. Once it is installed, go to your Extensions pane in Chrome and click "Allow this extension to run in incognito".

Then, enable incognito mode and try out:

http://browserspy.dk/browser.php
http://browserspy.dk/screen.php
and
http://browserspy.dk/date.php

comment:5 Changed 4 years ago by mikeperry

Eek, it turns out that it is possible to fingerprint that certain addons are installed by sourcing their chrome-extensions urls from page script. If the addon is installed, the page will source. If it is not installed, the page won't source and you can detect this by either catching an exception or registering a listener for onerror.

This is bad for Torbutton's undiscoverability requirement: https://www.torproject.org/torbutton/design/#undiscoverability

However, I'm guessing a lot of addons inject tags that source things from their own addons dir into pages they have permissions over.. Bleh. Maybe this is something we can use Web Request to handle.

comment:6 Changed 4 years ago by mikeperry

The second .crx update fixes a parse error on the last line that shouldn't have affected functionality.

comment:7 Changed 4 years ago by mikeperry

Ok, I just got back from my meeting with Adam Barth and Pam Greene at Google. Adam is familiar with Firefox js rootkit/closure busting techniques, and he tried out a few common ones but couldn't directly undo our hooks.

However, he was able to bypass them by doing anything that induced chrome to load an about:blank window, because the content scripts do not get applied. This includes:

<iframe src="about:blank" id="myframe"></iframe>
<script>
var frame = document.getElementById("myframe");
window.alert(frame.contentWindow.screen.availHeight);
</script>

But also, more subtly:
<script>
function haxor() {

var win =3D window.open('/');
alert(win.screen.availHeight);

}
</script>
<button onclick=3D"haxor()">Try to haxor</button>

More directly, encoding anything into a data url and throwing it in the url bar or elsewhere is also not covered by their content script injection:

<html><script>alert(window.Date());</script></html>

So we've got to convince chrome to allow us to inject content scripts into about:blank windows and data urls.

The good news is that race conditions do not seem possible with our approach. I put a pretty fat delay loop into the content script before doing the injection, and page script did not load first.

comment:8 Changed 4 years ago by mikeperry

Also, my brother pointed out that the chrome.google.com extension gallery is exempt from content script injection, for abuse concerns. Similar exemptions apply to other about: urls.

This means that we will have to ensure that Web Request will allow us to block all requests to this page, and to special about: urls, so that we can display a confirmation dialog to the user before they are (forcibly) navigated to them to be fingerprinted.

Changed 4 years ago by mikeperry

Apply content scripts to iframes. Update version to 0.0.4

comment:9 Changed 4 years ago by mikeperry

Two potential filed chromium bugs that could ruin our day if they are fixed:

https://code.google.com/p/chromium/issues/detail?id=51496
https://code.google.com/p/chromium/issues/detail?id=42053

We *may* be able to wrap every variable we declare inside an additional anonymous lambda to protect against this use of "with", though, so long as chrome doesn't *also* add a way to walk a javascript scope chain.

comment:10 Changed 4 years ago by mikeperry

We also need to keep an eye on the behaviors of Object.call(), Object.apply() and Function.bind():
http://www.digital-web.com/articles/scope_in_javascript/

So far they don't seem to cause us any trouble because of how V8 treats 'this' and var declarations.

Also, two more related bugs we need to track:

https://code.google.com/p/chromium/issues/detail?id=31590
https://code.google.com/p/chromium/issues/detail?id=42476

comment:11 Changed 4 years ago by mikeperry

We should also keep an eye on this query to keep us appraised of plans to add scope-walking capabilities to V8:

https://code.google.com/p/chromium/issues/list?can=2&q=__parent

So far there are no tickets open for it, which is good.

comment:12 Changed 4 years ago by mikeperry

Thanks, trac. There should be two underscores after parent in that query. It should read "parent"

https://code.google.com/p/chromium/issues/list?can=2&q=__parent

Changed 4 years ago by mikeperry

Document scoping and potential issues.

Changed 4 years ago by mikeperry

Clean up code+comments a bit more.

comment:13 Changed 4 years ago by mikeperry

We should also keep an eye on the registerProtocolHandler bug: https://code.google.com/p/chromium/issues/detail?id=11359

Shouldn't cause us serious problems, but useful to track.

comment:14 Changed 4 years ago by mikeperry

Robert Hogan just landed us a window.screen spoofing option in WebKit, so we may not need to wrap that in our javascript hooks:

https://bugs.webkit.org/show_bug.cgi?id=41802

comment:15 Changed 3 years ago by mikeperry

Note: See TracTickets for help on using tickets.