[tbb-dev] Is JS monkey patching viable as a fingerprinting countermeasure?

Arthur D. Edelstein arthuredelstein at gmail.com
Mon Sep 1 20:37:40 UTC 2014

On Mon, Sep 1, 2014 at 1:15 PM, Mike Perry <mikeperry at torproject.org> wrote:
> Arthur D. Edelstein:
>> Hi All,
>> I'm wondering about the history of JS fingerprinting mitigation in Tor
>> Browser. What prompted the change of approach from JavaScript hooks to
>> C++ patches? I had read something about a race condition discovered,
>> but I haven't found more details.
>> I've been thinking about the idea of developing a C++ patch for Tor
>> Browser (and Firefox) that allows extensions to securely replace
>> arbitrary members (functions and properties) of the global window
>> object at runtime, before content is loaded. By "secure" I mean that,
>> by design, there would be no workaround for content scripts to access
>> the original window object members. (Maybe this capability already
>> exists -- I don't know.)
>> The advantages of this monkey patching approach over addressing
>> fingerprinting vulnerabilities with C++ patches is
>> (1) it would (I think) simplify fingerprinting countermeasures, and
>> (2) it would reduce the number of Firefox C++ patches that Mozilla
>> needs to accept.
>> Is this idea worth pursuing further?
> Possibly, but even if we address all the race conditions and edge cases
> (like javascript: urls and data: urls that contain script), historically
> JS hooking is very fragile, with lots of ways to undo/break it cropping
> up regularly in new releases.
> IIRC, such "secure"/"sealed"/"non-configurable"/non-revocable hooking
> recently became standardized as part of Object.defineProperty,
> Object.seal, and friends, but this may still have issues. Some things
> might still be forbidden from being overridden for various reasons. The
> last time I went down this road, it was an endless sinkhole of issues,
> and I only did it because patching the browser was not an option at that
> point.
> On top of this, it doesn't allow us to cleanly hook events, callback
> parameters, and other async things. In some cases, we can probably work
> around this by hooking the callback registration to install our own
> wrapper callbacks that alter their args before passing them in to the
> registered callback, but that too takes care to ensure that the true
> arguments cannot be discovered by inspecting the callchain and
> associated parent scopes from inside the final content's callback.
> It also won't help with CSS-based vectors for fingerprinting, or
> complicated interactions between styling and JS.
> It's something to consider if it really looks like Mozilla won't take
> any of our fingerprinting defenses, but I think we should continue to
> prioritize direct patches for now.
> That said, if you see a clean way to create an API to do secure script
> injection and feel like hacking it up real quick, feel free. It may
> prove useful eventually, but I suspect we'll uncover a whole slough of
> surprises once we actually try to use it. We'll probably also need
> regression tests in-tree for every single function/callback/property we
> hook, to make sure that an implementation change doesn't suddenly break
> our ability to hook something in the way we want.

You make a compelling argument for the direct C++ patches. My thinking
mainly was to use JS patches as a stopgap while C++ patches are being
developed, but after your explanation it's not so clear to me that JS
patches will be any easier or quicker.

More information about the tbb-dev mailing list