Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Q: Canvas fingerprint when using RFP + CanvasBlocker #767

Closed
quantizzed opened this issue Jul 28, 2019 · 12 comments
Closed

Q: Canvas fingerprint when using RFP + CanvasBlocker #767

quantizzed opened this issue Jul 28, 2019 · 12 comments

Comments

@quantizzed
Copy link

Hi!

I'm a bit confused with the way canvas fingerprint is handled when using RFP.

IIRC, when RFP is enabled, Firefox is supposed to:

  • request the user's permission whenever a website tries to extract the canvas fingerprint;
  • spoof the real fingerprint with a constant value.

However, I have an impression that at least some websites (e.g. Panopticlick and Browserleaks) are able to read the canvas fingerprint without directly asking for permission or even when I have explicitly blocked its extraction.

Now, I also have the CanvasBlocker addon set up to fake API readouts, and it seems that it's only able to do its job when I explicitly allow a website to extract the canvas fingerprint. But whenever a site is able to bypass my permission, it just gets that constant value supplied by RFP.

Where am I being wrong, and is it possible to make Firefox always let CanvasBlocker handle the faking (and keep RFP enabled at the same time)?

@Thorin-Oakenpants
Copy link
Contributor

🔻 FF58

  • 967895 prompt (site permission) before allowing canvas data extraction
    • FF59: 1413780 when RFP=true include canvas in site permissions panel
    • FF59: 1376865 reduce canvas prompt fatigue by only prompting when user initiated (controlled by a temp pref privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts )

request the user's permission whenever a website tries to extract the canvas fingerprint

Only when user initiated

is it possible to make Firefox always let CanvasBlocker handle the faking (and keep RFP enabled at the same time)

No. See #350 > Canvas.

If you're using RFP, then you need to look the same as other RFP users. As soon as you change something, then you stand out. It's an all-in buy-in or nothing.

@kkapsner can offer more insight: CB does not alter the RFP canvas, which as you correctly said, is static (it's a white canvas) - but I'm pretty sure that's by design: I'm not an extension developer, but I think an extension could override it. Example: extensions overriding RFP when it comes user agent/navigator properties: because the extension is the last one to modify it. A am not suggesting at all that this (RFP canvas override) be implemented as an option, just checking in with kkapsner for clarification

@kkapsner
Copy link

CanvasBlocker sees the actual content of the canvas and it then fakes the output. BUT RFP kicks in afterwards (I do not investigate the exact details as it's the way I would like it to be - I do not even know if it's possible to have it in another way and if so I will not implement it in CB). So the page only sees the canvas content if RPF is disabled or the site is allowed to use canvas.

You can have a little peak behind the curtain by enabling RFP, storing the notification data and the image data for the notification in canvasblocker (two settings of CB) and go to https://canvasblocker.kkapsner.de/test/test.html
On the page you will see the white output the page sees and in the notification you see that CB got the real canvas content.

@quantizzed
Copy link
Author

If you're using RFP, then you need to look the same as other RFP users.

Well, there are probably very few RFP users overall, and, therefore, a good chance to be the only one on a randomly picked site, so I thought being always unique with a new canvas fingerprint would be a better strategy, than being persistently unique.

See #350 > Canvas.

Thanks, this seems to answer all my questions. So, IIUC,

  • CB is currently pretty much useless, since having RFP enabled results in giving off the static fingerprint value anyway;
  • CB comes into play only when I explicitly allow access to my real canvas, and serves a fake value instead;
  • always faking by default is not yet possible, until Firefox introduces a pref for a default permission.

@Thorin-Oakenpants
Copy link
Contributor

Thorin-Oakenpants commented Jul 28, 2019

Well, there are probably very few RFP users overall, and, therefore...

Your only hope is that the set of users you are in, conform to a standard. Uptake is important (obviously: that's what entropy is all about), but not as important as not breaking the rules and diverging. As soon as you diverge: you splinter from the main pack: and stand out.

Assuming (thanks @kkapsner for explaining that it's not ) you can alter RFP's canvas (aside from allowing site exceptions)... lets take the case of RFP vs RFP with canvas always randomized: even per domain and even per tab/session, so it's consistent within that domain). It is trivial to detect that you are a RFP user: now your canvas will not be the default white canvas spoof: therefore you are now (ultra super highly likely) in a much smaller set than if you had just left RFP alone. I say highly likely, because it is not impossible that 50% or more of RFP users would do this. But it's not going to happen.

This is why RFP needs to lock down people fiddling with it and thinking they know better. This is why Tor Browser tell people not to fiddle with settings, and not to install extensions.

PS: This is not about the effectiveness of raising entropy vs lowering it. There are pros and cons to both. RFP chose to lower canvas entropy.

@Thorin-Oakenpants
Copy link
Contributor

always faking by default is not yet possible

Yes it is. RFP fakes by default: as a white canvas. I think you meant randomize.

@crssi
Copy link

crssi commented Jul 28, 2019

CB is currently pretty much useless

Not true.

  1. If you decide to allow access to canvas (due to breakage otherwise), then CB kicks in.
  2. CB is much much more than only canvas blocker. It covers also other vectors.

@quantizzed
Copy link
Author

  1. If you decide to allow access to canvas (due to breakage otherwise), then CB kicks in.

But before I allow access to canvas, I've already given off RFP's static fingerprint.

  1. CB is much much more than only canvas blocker. It covers also other vectors.

You're right, of course, my bad, I've missed this important point.

@e-t-l
Copy link

e-t-l commented May 3, 2021

CB is much much more than only canvas blocker. It covers also other vectors.

Sorry if this is a noob question, but what does the CanvasBlocker extension do besides being... a canvas blocker?

@rusty-snake
Copy link
Contributor

Protected "fingerprinting" APIs:

  • canvas 2d
  • webGL
  • audio
  • history
  • window (disabled by default)
  • DOMRect
  • TextMetrics
  • navigator (disabled by default)
  • screen

More information on fingerprinting can be found at:

@Thorin-Oakenpants
Copy link
Contributor

RFP Canvas is all or nothing. You can set a site exception via the canvas icon in the urlbar: for session or permanently

CB on the other hand, does not kick in until RFP relinquishes it: so it may be useful depending on the site and what it actually does: e.g. any change of pixels will distort the image: but at least it's subtle enough to not break a lot of functionality. e.g. some sites only use canvas for legit purposes. CB can still whitelist a site. And sites you allow a real canvas through that is used in fingerprinting, is limited to those site you allow it - not all sites: and the canvas fingerprint would need to be universal across those sites, and a lot of fingerprinting scripts are already blocked. But, FPing scripts are becoming embedded into site functionality: meaning you can't just block a js file any more.

So

  • RFP (totally random and unusable) -> CB (subtle, probably usable) ->CB whitelist (real value)
  • low risk: only one metric (canvas), i.e granular, exposed to select sites and select scripts

The other CB protected metrics are up to you. Extensions can generally only fool naive scripts. Some metrics the real values can leak, others they don't (which is very important), but they all reveal themselves in ways built-in browser solutions don't: the extensions themselves give off a fingerprint: e.g. degree of randomization in canvas, what APIs they target/block, etc.

Don't overthink it: most scripts are naive: they need to be fast, and they have plenty of low hanging fruit to pick from. It will however evolve. That said, I would not use CB metrics that are already protected by RFP, except canvas as a intermediate fallback.

User agent spoofing doesn't even fool a lot of naive scripts. Screen is counterproductive. The rest is up to you. Advanced scripts can spot them anyway: so it becomes, do I want to protect the real value vs being one of a very few: and that comes down to the metric and the real-world entropy. Not all advanced scripts are the same: so the more you randomize, the more the chance one is not picked up on, and alters the fingerprint.

So if for example you use webgl (arkenfox disables it since there is no current built-in browser full solution), then protecting the real value is a must: webgl entropy is extremely high: probably unique in very advanced scripts. Audio on the other hand is very low entropy: more like a possible 10 values in Firefox. So which is better, one of 10 values, or one of a very few users who spoof audio (assuming that a script bothers to detect audio spoofing).

I do not think there is any harm in using CB's textmetrics, domrect, audio and webgl randomizing: but of those, only webgl IMO is a threat: the others are likely to be the result of other settings/OS/math-libraries/builds/fonts-set-by-language+locale etc: in other words they are equivalency, and when you alter that, you stand out (to advanced scripts).

so

  • on one hand it takes almost nothing for an advanced script to pick up on missing equivalency
  • but on the other, if you're already exposing the web extension e.g. via webgl, then you might as well go whole hog and fuck up audio, textmetrics and domrect in the hopes they trick the script

sorry for the non-answer: ultimately we require built-in browser solutions to properly protect, and for those solutions to be enforced and shielded from end-users changing them, and for the browser solution to be used by large numbers - but that doesn't mean that RFP or other solutions are useless

@Plethonis
Copy link

Plethonis commented May 8, 2021

In your oppinion, for web anonimity purposes, I want to ask:

  • Which is the better way between fake and block? And if it's the "fake one", which one between: none / non persistent / constant / persistent, do you suggest?

  • Also, is there any good reason to protect window API? Or is better off?

  • About "Canvas API" section, this is how do you suggest?

  • And my last question is about the "Fake the alpha channel" function. Should this be On or Off ?

(I already use RFP in Firefox and soon I will also add the arkenfox user.js)

ultimately we require built-in browser solutions to properly protect, and for those solutions to be enforced and shielded from end-users changing them, and for the browser solution to be used by large numbers - but that doesn't mean that RFP or other solutions are useless

I will send this to the Firefox team, and maybe it will be a reality in the future.
Thanks for the explicit information.

@Thorin-Oakenpants
Copy link
Contributor

I don't use CB: but I would suggest just using the canvas protection with it's default settings


There's no need to send anything to the "Firefox team" - everyone is already aware of everything they need to know


It is important to protect the real value. It is not important to hide that you're lying. Blocking is a last solution, no one wants that. Faking is much better. Faking comes in two main flavors: static and randomized. All randomizing can be detected [there are some exceptions to this rule, but in a set of RFP or Brave or TB users, that doesn't apply: you can infer it]. You most certainly cannot hide that canvas is altered or randomized

Everything below is specifically about canvas

Faking like RFP used to do as a static result (all white canvas), is pretty much the same as blocking: totally unusable, you might as well block it

Randomizing as RFP does now is better, as it can fool naive scripts. RFP does this per execution. So two checks with different results reveals this. RFP is not trying to hide. The result is still unusable, as RFP also totally randomizes: all pixels, all channels, big changes in rgba values. It does this because when canvas protection was added there were most likely time constraints and engineering issues, and definitely real concerns over protecting any random seeding. RFP is built for Tor Browser after all. And canvas use four years ago wasn't the same as it is today: e.g. sites today even use canvas where they don't need to such as the ability to upload and display images. Just a fact of life out of anyone's control. At the time, RFP added a site exception (session or permanent) for canvas to alleviate this

RFP doesn't care about persistence (per eTLD+1) or protecting any random seed, so it's irrelevant to RFP

A canvas site exception is very granular. It doesn't affect other RFP measures even on that site. The "real" canvas would only leak on those few sites you allowed an exception: and over those sites, the scripts for canvas would need to be the same. The threat is somewhat minimized. There is a reason canvas does not have a default off.

Extensions, and Brave, that use subtle randomizing are trying to auto-solve the breakage. And that's good, because canvas use is growing and breakage sucks. This is where persistence per eTLD+1 and protecting the random seed come into play. Brave persists over a browser session. I think CB persists only as long as the site is open in any tab. This persistence is always detectable, i.e that it exists, not whether it is per session or per eTLD+1 or while an eLTD+1 is open. What channels are changed is detectable. What % of pixels is detectable. What range of subtleness in value changes is detectable. Even what canvas size you have exceptions for is detectable. Not that all scripts would check for all this: but you can absolutely fingerprint the noise (which is not an issue for built-in browser solutions like Brave: everyone is the same).

Which one is the right approach, who really knows. Maybe some hybrid tied to a slider, like Tor Browser could use standard (subtle) vs safer (full on), or like when you allow a site exception for canvas fall back to subtle random. Along with heuristics and user gestures (not keen on this), and discoverability (e.g. of the canvas urlbar icon)

Maybe RFP/TB will entertain the idea of using subtle randomizing, but it's risky IMO. Brave's first iteration went for over a year before someone told them it was too subtle. This is now fixed. But it is still probably susceptible to being averaged - this is probably OK for a mainstream browser user's threat model, but not for Tor Browser (which is what RFP is designed for). Don't get me wrong, breakage like canvas turns people off, and protection against very advanced scripts and determined attackers requires uptake: so Mozilla need to solve this canvas issue sooner rather than later. They're working on it, it's just slow and not super high priority given more immediate fixes and bigger payoffs elsewhere

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants