Opened 5 years ago

Closed 4 years ago

#13875 closed defect (fixed)

Tor Browser DPI spoofing omitted window.devicePixelRatio

Reported by: isis Owned by: tbb-team
Priority: High Milestone:
Component: Applications/Tor Browser Version:
Severity: Keywords: tbb-fingerprinting-resolution, tbb-testcase, tbb-firefox-patch, TorBrowserTeam201505R, GeorgKoppen201505R
Cc: isis, gk, mikeperry, pete@…, poly@…, brade, mcs, arthuredelstein Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

I suspected that the test for DPI at browserspy.dk was not functioning properly, so I kind of dared people on Twitter to come up with a PoC for using relative element sizing to infer true DPI, beating Tor Browser's DPI-spoofing. 0xPoly reported that the true DPI size can be inferred via such a mechanism, and provided the following example PoC:

page.html:

<div id='testdiv' style='height: 1in; left: -100%; position: absolute; top: -100%; width: 1in;'></div>

page.js:

var devicePixelRatio = window.devicePixelRatio || 1;
dpi_x = document.getElementById('testdiv').offsetWidth * devicePixelRatio;
dpi_y = document.getElementById('testdiv').offsetHeight * devicePixelRatio;

alert(dpi_x);

In Tor Browser, even on high-density displays, the DPI is correctly spoofed to 96x96, and the above code does alert('96'). However, if the user changes the zoom level, i.e. via Ctrl-+ or Ctrl--, then the above Javascript will detect a non-96x96 DPI. When I tested (on a machine with a 96x96 DPI display), zooming once led to alert('115.20000457763672'), however that '115.20000457763672' stayed the same if I scaled the browser window size differently and reloaded the page (keeping the zoom at the same level). Peter Todd reported that detecting the zoom level also works on a high-density display.

This may particularly be a problem on huge displays, or any other displays probably viewed from a greater-than-arms-length distance, where the users are constantly zooming in.

Possibly related: #7256

Child Tickets

Change History (26)

comment:1 Changed 5 years ago by isis

Cc: pete@… added

comment:2 Changed 5 years ago by mikeperry

Apparently this may also be an issue if the user tweaks some Windows DPI scaling option? Unclear what that is or what that means. https://twitter.com/0xPoly/status/539593347078164480

I'm less concerned about zoom being detectable, especially since the process of zooming will cause all sorts of CSS reflows that will likely be detectable no matter what, at least with how zoom is currently implemented.

There's also #4316 though, which is perhaps more concerning. I wonder if #4316 is still even an issue though. That sure is an old ticket.

comment:3 in reply to:  2 Changed 5 years ago by isis

Replying to mikeperry:

Apparently this may also be an issue if the user tweaks some Windows DPI scaling option? Unclear what that is or what that means. https://twitter.com/0xPoly/status/539593347078164480


I didn't understand that either… perhaps that person will comment more. Thanks, mikeperry, for cataloging that tweet for me; I nearly forgot to add it to the ticket.

comment:4 Changed 5 years ago by poly

hello, poly here. Sorry for the late reply, I'm just getting used to the trac system.

I created a writeup (with photos!) to clarify the windows dpi scaling and another POC to show that the actual zoom level can be inferred. Skip to the description section for the relevant stuff. Can anyone try the second POC and comment on how reliable it is?

http://darkdepths.net/dpi-leaks-in-tor-browser.html

comment:5 Changed 5 years ago by poly

Cc: poly@… added

comment:6 in reply to:  4 Changed 5 years ago by gk

Resolution: duplicate
Status: newclosed

Replying to poly:

hello, poly here. Sorry for the late reply, I'm just getting used to the trac system.

I created a writeup (with photos!) to clarify the windows dpi scaling and another POC to show that the actual zoom level can be inferred. Skip to the description section for the relevant stuff. Can anyone try the second POC and comment on how reliable it is?

I did often get no zoom level back while zooming around but maybe that's just because the zoom level was not exactly hard-coded. But I could confirm that #4316 is fixed, thanks. That said this ticket is a duplicate of #8076.

comment:7 Changed 5 years ago by mikeperry

Resolution: duplicate
Status: closedreopened

comment:8 Changed 5 years ago by mikeperry

Reopened this to dup the other way, ie: calling #8076 the dup (or simply closed, as this ticket contains the results of investigation).

comment:9 in reply to:  8 Changed 5 years ago by gk

Keywords: tbb-testcase tbb-firefox-patch added
Priority: normalmajor
Summary: Tor Browser DPI spoofing is broken if the user changes zoom levelTor Browser DPI spoofing is broken

Replying to mikeperry:

Reopened this to dup the other way, ie: calling #8076 the dup (or simply closed, as this ticket contains the results of investigation).

Well, the investigation is not over, there is still the CSS case and the things we wanted to study (large amount of variability) which is why I duped it the way I did. That said I don't feel so strongly that I'd start duping this over again but I think we should make sure that a fix we provide for this particular PoC catches all the other DPI-spoofing-is-broken-scenarios, too.

Some relevant resources from #8076:

https://developer.mozilla.org/en-US/docs/CSS/resolution
https://bugzilla.mozilla.org/show_bug.cgi?id=564815 (the devicePixelRatio bug)

Oh, and while I am at it: the issue is visible with a default Tor Browser without messing with the zoom at all (which is why I changed the summary and raised the priority).

comment:10 Changed 5 years ago by mikeperry

Keywords: tbb-fingerprinting-resolution added; tbb-fingerprinting removed

comment:11 Changed 5 years ago by mcs

Cc: brade mcs added

comment:12 Changed 4 years ago by arthuredelstein

Cc: arthuredelstein added

comment:13 Changed 4 years ago by arthuredelstein

Here's a fixup to our #5856 patch that spoofs window.devicePixelRatio to 1 for content scripts:

https://github.com/arthuredelstein/tor-browser/commit/a5648c8d80f396caf294d761cc4a9a76c0b33a9d

I ran into this issue while working on #14429 (and #7256).

comment:14 Changed 4 years ago by arthuredelstein

Keywords: TorBrowserTeam201504R added
Status: reopenedneeds_review

comment:15 Changed 4 years ago by mcs

Kathy and I looked at the patch and it looks good. Do you think this addresses all of the issues for this ticket?

comment:16 in reply to:  15 Changed 4 years ago by arthuredelstein

Replying to mcs:

Kathy and I looked at the patch and it looks good. Do you think this addresses all of the issues for this ticket?

As far as I am aware. I believe your patch for #2875 already took care of the "-moz-device-pixel-ratio" and "resolution" media queries:
https://gitweb.torproject.org/tor-browser.git/commit/?h=tor-browser-31.6.0esr-4.5-1&id=958aa2e6bcb71f497ec9253fdf9b6dfc1553225c

Last edited 4 years ago by arthuredelstein (previous) (diff)

comment:17 Changed 4 years ago by mikeperry

Keywords: MikePerry201504R added

comment:18 Changed 4 years ago by mikeperry

Resolution: fixed
Status: needs_reviewclosed
Summary: Tor Browser DPI spoofing is brokenTor Browser DPI spoofing omitted window.devicePixelRatio

Also looks good to me. poly: feel free to reopen this or open a new ticket if you notice any remaining issues. This fix will appear in 4.5-stable.

comment:19 Changed 4 years ago by arthuredelstein

Keywords: TorBrowserTeam201505R MikePerry201505R added; TorBrowserTeam201504R MikePerry201504R removed
Resolution: fixed
Status: closedreopened

It turns out my fix made it impossible for chrome code to read the true devicePixelRatio of a content window, which is needed for my patch in #14429 (and may be useful in general). So here's another fixup which continues to spoof devicePixelRatio for content code, but returns the true value for chrome code:

https://github.com/arthuredelstein/tor-browser/commit/7a4d6e2bf2b3cd0812b93dab5a899f2412340154

comment:20 Changed 4 years ago by arthuredelstein

Status: reopenedneeds_review

comment:21 Changed 4 years ago by mikeperry

My typical question with this IsCaller stuff: Is this property exported to WebSockets? What happens there?

Also, how about scripts inside blob URIs from the URL bar? And blob URIs from an iframe?

comment:22 in reply to:  21 Changed 4 years ago by arthuredelstein

Replying to mikeperry:

My typical question with this IsCaller stuff: Is this property exported to WebSockets? What happens there?

Are you thinking of WebWorkers? I ran a quick manual test, and devicePixelRatio is not exposed to WebWorkers.

Also, how about scripts inside blob URIs from the URL bar? And blob URIs from an iframe?

Yeah, again I think you're right that the IsCallerChrome() call is dangerous, and I should have thought about these possibilities more. Also it worries me that using IsCallerChrome to prevent leaks to content is not very future-proof, even if we can confirm that it is airtight now.

An alternative method for getting the "true zoom level" of a content window, instead of

let trueZoom = gBrowser.contentWindow.devicePixelRatio;

is to call

let trueZoom = gBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDOMWindowUtils)
                       .screenPixelsPerCSSPixel;

So here's an alternative patch that leaves nsGlobalWindow::GetDevicePixelRatio with the IsChrome call and instead fixes nsDOMWindowUtils::GetScreenPixelsPerCSSPixel so that it isn't spoofed when "privacy.resistFingerprinting" is activated. The latter call is only available from chrome code.

https://github.com/arthuredelstein/tor-browser/commit/4c316cacb6383c9b60606630ef331301fa51da10

Last edited 4 years ago by arthuredelstein (previous) (diff)

comment:23 Changed 4 years ago by mikeperry

Given that we only need this for #14429, I am going to defer this until 5.0a1.

comment:24 Changed 4 years ago by gk

Keywords: GeorgKoppen201505R added; MikePerry201505R removed

comment:25 Changed 4 years ago by gk

Looks good to me.

comment:26 Changed 4 years ago by mikeperry

Resolution: fixed
Status: needs_reviewclosed

Ok, this is merged into tor-browser-31.7.0esr-5.0-1 for 5.0a1.

Note: See TracTickets for help on using tickets.