I checked https://bugzilla.mozilla.org/show_bug.cgi?id=884226: This brings a new canvas context property (willReadFrequently) that enables reading from a software backend instead of a hardware "accelerated" one, which turns out to be super-slow for some cases.
So, canvas reads may get faster, but no fingerprinting risks that I can see.
Also interesting is #962517 which brings a chrome only HW-acceleration-disabled canvas and explains the HW backend problem better in the context of FFOS.
HitRegions are about defining clickable regions in canvas, similar to image-maps for elements (e.g. using & ). Although one may potentially exploit the pixel-level differences in region boundaries (similar to isPointInPath method AddThis was using) it requires user interaction (click or hover) and doesn't look like a reliable fingerprinting vector.
Also there's a switch canvas.hitregions.enabled, and it is disabled by default in ESR31.
I checked https://bugzilla.mozilla.org/show_bug.cgi?id=884226: This brings a new canvas context property (willReadFrequently) that enables reading from a software backend instead of a hardware "accelerated" one, which turns out to be super-slow for some cases.
If a browser has both accelerated and non-accelerated canvases, they probably don't render things identically. You could draw the same fingerprinting issue in both and hash them together, and thereby get more discriminating power than one canvas alone.
I agree that willReadFrequently doesn't add any new fingerprinting power, because in its absence you just have to game whatever heuristic decides whether you get an accelerated or non-accelerated canvas.
I checked https://bugzilla.mozilla.org/show_bug.cgi?id=884226: This brings a new canvas context property (willReadFrequently) that enables reading from a software backend instead of a hardware "accelerated" one, which turns out to be super-slow for some cases.
If a browser has both accelerated and non-accelerated canvases, they probably don't render things identically. You could draw the same fingerprinting issue in both and hash them together, and thereby get more discriminating power than one canvas alone.
I agree that willReadFrequently doesn't add any new fingerprinting power, because in its absence you just have to game whatever heuristic decides whether you get an accelerated or non-accelerated canvas.
Yep, makes it easier to get a 2-in-1 canvas fingerprint from standard browsers.
But it's not a threat for Tor Browser, I suppose. Since TB returns a white canvas regardless of HW/SW backend.
Kathy and I also reviewed the canvas APIs. Here are a few of our observations:
The willReadFrequently canvas option is disabled by default (the gfx.canvas.willReadFrequently.enable pref must be added with the value true) so we do not need to worry about this.
We have not done anything to block use of isPointInPath() and isPointInStroke(). Do we need to block these?
We have not done anything to block use of measureText(). Theoretically, it could be used to detect differences based on available fonts or rendering differences. Do we need to block this?
In ESR31, ToBlob() accepts options to allow callers to specify encoding options such as JPEG quality. Kathy and I do not think this is a fingerprinting vector since, by default, white image data is returned.
Kathy and I also reviewed the canvas APIs. Here are a few of our observations:
We have not done anything to block use of isPointInPath() and isPointInStroke(). Do we need to block these?
I could not find any way to exploit those two for fingerprinting, but better someone else give a shot too.
Some canvas fingerprinting scripts found to use isPointInPath() with "even-odd" winding rule, but I think this was just to check browser support - will be same for all TBs. Unless someone says "the internal representations of the paths may depend on the graphics stack too!"
One could use these two functions to probe system fonts, if adding text to the current path or stroke was possible. I tried strokeText() and fillText() followed by isPointInStroke() and isPointInPath() but it didn't work out.
We have not done anything to block use of measureText(). Theoretically, it could be used to detect differences based on available fonts or rendering differences. Do we need to block this?
Wow, that's a good catch! I think this should certainly be blocked.
Kathy and I also reviewed the canvas APIs. Here are a few of our observations:
We have not done anything to block use of isPointInPath() and isPointInStroke(). Do we need to block these?
I could not find any way to exploit those two for fingerprinting, but better someone else give a shot too.
Some canvas fingerprinting scripts found to use isPointInPath() with "even-odd" winding rule, but I think this was just to check browser support - will be same for all TBs. Unless someone says "the internal representations of the paths may depend on the graphics stack too!"
It might be possible to get some mileage out of floating-point precision issues. For example, path.html draws quarter-circles in different ways (with arc and bezierCurveTo and quadraticCurveTo) and with different transformation matrices, and then tests points right on the perimeter of the circle.
I see different fingerprints in different versions of Firefox on the same system, and the same version of Tor Browser on different operating systems. I didn't get different fingerprints for the same Tor Browser on the same OS, but I only tried three installations.
The fingerprint I get with Tor Browser 4.0-alpha-2 on Debian is:
arc( T F F F T T ) ( T F F F T T ) ( T F F F T T )arc prerotated( F F F T T T ) ( F F F T T T ) ( F F F T T T )bezierCurve( T F F F T T ) ( T F F F T T ) ( T F F F T T )bezierCurveTo prerotated( F F F T T T ) ( F F F T T T ) ( F F F T T T )quadraticCurve( T T T T T T ) ( T T T T T T ) ( T T T T T T )quadraticCurve prerotated( F F F T T T ) ( F F F T T T ) ( F F F T T T )
We can guess that the underlying representation for arc is a cubic Bezier, because the corresponding rows match. The one for Firefox 31 on the same Debian is a little different:
arc( T F F F T T ) ( T F F F T T ) ( T F F F T T )arc prerotated( F F F T T T ) ( F F F T T T ) ( F F F F T T )bezierCurve( T F F F T T ) ( T F F F T T ) ( T F F F T T )bezierCurveTo prerotated( F F F T T T ) ( F F F T T T ) ( F F F F T T )quadraticCurve( T T T T T T ) ( T T T T T T ) ( T F T F T T )quadraticCurve prerotated( F F F T T T ) ( F F F T T T ) ( F F F F T T )
Tor Browser 4.0-alpha-1 on Windows 8 is:
arc( T T T T T T ) ( F T T T T T ) ( F T F F F T )arc prerotated( F F F T T T ) ( F F F T T T ) ( F F T T F T )bezierCurve( T T T T T T ) ( F T T T T T ) ( F T F F F T )bezierCurveTo prerotated( F F F T T T ) ( F F F T T T ) ( F F T T F T )quadraticCurve( T T T T T T ) ( F T T T T T ) ( F T F F F T )quadraticCurve prerotated( F F F T T T ) ( F F F T T T ) ( F F T T F T )
The fact that the result of isPointInPath can change just by applying a different transformation matrix (even though the test point gets multiplied by the same matrix) shows that there are probably some measurable precision issues. Whether they could ever distinguish the same Firefox on the same OS, I don't know.
Wow, that's a good catch! I think this should certainly be blocked.
Using the measureTextFP.html page that I just attached, the results we generated are interesting. It seems like the approach used to fix #2872 (closed) should apply to canvas measureText() as well. And adjusting the browser.display.max_font_attempts and browser.display.max_font_count prefs does significantly reduce the number of unique measureText() values a web page can generate.
Brilliant! I think this also makes fixing the multi-frame issue in #5798 more important.
Since it is the font-limit that bounces this attack, and one can embed multiple canvases in different iframes.
BTW I just remember that I once tested if font-limits apply to canvas as well:
http://jsbin.com/ferit/
As your findings also confirm the limits apply to canvas, which is good.
Back then apparently I was aware that measureText can be used for fingerprinting, but I guess I thought it gives more or less the same info as CSS offsetWidth/Height measurement. Having seen dcf's demo with transformations (comment 7), now I'm not very sure about that...