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

Canvas context method getImageData is producing some inconsistent color values in a blank canvas. #9591

Closed
ghost opened this issue May 3, 2020 · 22 comments
Labels
closed/invalid needs-more-info The report requires more detail before we can decide what to do with this issue.

Comments

@ghost
Copy link

ghost commented May 3, 2020

Description

Canvas context method getImageData is producing some inconsistent data values in a blank canvas. It's always the green color value and it is sometimes set to 1. It should always be 0.

Steps to Reproduce

Here is a script to log the results:

<canvas id="mycanvas" width="2" height="5"></canvas>
<script>
	var canvas = document.getElementById( "mycanvas" );
	var context = canvas.getContext( "2d" );
	var data = context.getImageData( 0, 0, 2, 5 ).data;
	for( var i = 0; i < data.length; i += 4 ) {
		var r = data[ i ];
		var g = data[ i + 1 ];
		var b = data[ i + 2 ];
		var a = data[ i + 3 ];
		console.log( r, g, b, a );
	}
</script>

Actual result:

0 1 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 1 0 0
0 1 0 0
0 0 0 0
0 0 0 0

Expected result:

0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

Reproduces how often:

Every time.

Brave version (brave://version info)

Version 1.8.86 Chromium: 81.0.4044.129 (Official Build) (64-bit)

@Xyncgas
Copy link

Xyncgas commented May 3, 2020

Chromium too?

@ghost
Copy link
Author

ghost commented May 3, 2020

This only occurs in the Brave browser, I tested in Edge, Firefox, and Chrome, none of them had this issue.

@srirambv
Copy link
Contributor

srirambv commented May 4, 2020

Have you tried disabling fingerprinting or setting it to allow all fingerprinting and checked?

@srirambv srirambv added the needs-more-info The report requires more detail before we can decide what to do with this issue. label May 4, 2020
@pes10k
Copy link
Contributor

pes10k commented May 5, 2020

This is not a bug, this is Brave's farbling related fingerprinting protections in place #9186

More info here: https://brave.com/whats-brave-done-for-my-privacy-lately-episode3/

@pes10k pes10k closed this as completed May 5, 2020
@pes10k
Copy link
Contributor

pes10k commented May 5, 2020

further you should get a slightly different result, per session

@ghost
Copy link
Author

ghost commented May 5, 2020

This is really annoying. No other browser does this and this means I will have to add specific code on my website just to accommodate this. I highly recommend finding another way to protect against fingerprinting.

Is there a way I can file an official complaint against this feature?

@pes10k
Copy link
Contributor

pes10k commented May 5, 2020 via email

@ghost
Copy link
Author

ghost commented May 5, 2020

It's for a paint tool so I need to read the image data to determine the pixel colors when implementing the paint bucket tool.

@pes10k
Copy link
Contributor

pes10k commented May 5, 2020 via email

@pes10k
Copy link
Contributor

pes10k commented May 5, 2020

Thank you for the image. This is very surprising, we're only altering the lowest bit in one color change, so you shouldn't be seeing black dots in the generated image, you should see, at the most extreme, extremely subtle color differences. Could you share the image before you apply any modifications / transformations to it (if thats not whats above)? Just want to make sure there isn't some bug hitting here.

I can adjust my algorithm to ignore an RGB value difference of 1 or 2 color values, but I was hoping to avoid that so it it would be more precise.

I understand the frustration, but I think you'll either need to ask users to disable fingerprinting protections on your page, or you'll need to change the algorithm. The unfortunate truth is that the vast majority of uses of canvas readback on the web are for fingerprinting, so we can't relax these protections without introducing significant privacy harm for users

@ghost
Copy link
Author

ghost commented May 5, 2020

The image is 100% generated using code. So there is no before image.

I've added this to my code, it seems to fix it.

if( navigator.brave.isBrave() && tolerance === maxDifference ) { tolerance -= 1; }

Thanks for your explanations.

@pes10k
Copy link
Contributor

pes10k commented May 5, 2020

@cstubbs50 great, im glad it helps! FWIW though navigator.brave.isBrave() returns a promise, so you're not actually checking anything there. You'll also throw an exception there if you're running in some other browser. So you might just check for navigator.brave (since its unlikely anyone else will implement navigator.brave anytime soon). Hope that helps!

@pes10k
Copy link
Contributor

pes10k commented May 5, 2020

No, though thats also by design. We want to avoid sites trying to avoid randomized APIs when doing fingerprinting; the goal is to do fingerprinting protections / randomization w/o sites knowing whether its enabled or not. Otherwise, fingerprinters would just work around or ignore the values we poison

@Undoundoundo
Copy link

I don't mean to revive this Issue, but based on the blog post that finally mentions this ( I had originally posted the same problem at https://community.brave.com/t/canvas-todataurl-image-png-introduces-noise/120854/5 long before that post ) and the above replies, I'm led to believe that there should be a setting which would disable the introduction of these protective measures.

Could you detail exactly which setting of combination of settings that would be? Neither 'Shields down' nor specifically setting 'allow all fingerprinting attempts' seemed to do the trick.

I'm in a similar situation as OP; I generate images that require exact colors. When I turn the canvas to an image (via .toDataURL) for storage, and that resulting image is then loaded back into my site (technically there's also an internal part that passes the data around that way, but that could be avoided), my site complains that there's a bunch of pixels that don't match.

So, just like OP, I've had to essentially add a Brave Compatibility mode, detecting Brave through:
(navigator.brave && navigator.brave.isBrave()) and allowing a lowest bit difference in any of the RGB channels, while also presented this as a UI option in case there's any future forks of Brave or other browsers implementing this measure that would have the same issue. This does slow down some features of the site a little, and ultimately still causes any Brave Browser user to generate images that have this noise which may confound users of other browsers, but I understand that may be a price that some are willing to pay for privacy.

the goal is to do fingerprinting protections / randomization w/o sites knowing whether its enabled or not. Otherwise, fingerprinters would just work around or ignore the values we poison

But my site (though not my test page anymore, will have to figure out why) does detect the farbling of the canvas, and does work around it.. just not for any privacy-affecting purposes.

I have to admit I'm curious as to what type of fingerprinting this introduction of noise is intended to thwart, but this Issue may not be the place to do so.

@pes10k
Copy link
Contributor

pes10k commented May 27, 2020

@Undoundoundo yep, once the work described https://brave.com/whats-brave-done-for-my-privacy-lately-episode-4-fingerprinting-defenses-2-0/ is finished (anticipating, but not promising, 2-3 weeks) the fingerprinting shields control will switch from controlling the current "disable the feature" fingerprinting system, and will control the new farbling defenses.

So, exactly what you're asking for will be in place shortly :)

@daves-cz
Copy link

daves-cz commented Apr 1, 2021

Just felt in same issue. Function getImageData returns wrong values when fingerprint shield is on. Pretty dumb. It broke application, since it stores data in lower 3 bits of RGB data.

@pes10k
Copy link
Contributor

pes10k commented Apr 2, 2021

@daves-cz I appreciate your frustration, and am sorry for it. But unfortunately, pixel-perfect getImageData is used for fingerpritning far more often than it is for benign purposes, so we think this is the trade off best for our users (in default settings). FWIW, we are still pushing for other fixes here upstream and in the standard

@wbharding
Copy link

wbharding commented Jan 2, 2024

FWIW I'm another app owner whose users regularly email us because a web API that every other browser implements per spec is broken by Brave. Thus, Amplenote users who use Brave can't use our Graph View without experiencing inconsistent failures. There must be better ways to stop fingerprinting than to break essential web APIs?

As one proof point: note how this issue keeps getting referenced nearly every year. This is not a benign thing to break.

@bsclifton
Copy link
Member

cc: @ShivanKaul

@ShivanKaul
Copy link
Collaborator

I'm sympathetic to the legit use-cases here and understand the frustration, but canvas fingerprinting is a well-studied and widely deployed attack on user privacy [1][2][3]. This is why Brave tries to balance privacy and usability by randomizing lower order bits by default (users can toggle it off). Given that most users use Brave for best-in-class privacy, turning our protection off by default for this attack vector doesn't make sense to me.

@Xyncgas
Copy link

Xyncgas commented Jan 4, 2024

In other words for developers who are looking for the removal of this feature, can simply invent a finger printing method to render the protection unusable or unable to protect, it should put brave to removing this protection at high priority

Instead of asking for removal simply do arm race can be a way to solve the problem yourself

@wbharding
Copy link

I understand that users (including me, for personal use) pick Brave for privacy. But I also don't want to use a browser that breaks core functionality in the apps that I use. Yes, users can toggle it off, but they have to discover that it is Brave that is breaking the app's (validly-implemented) functionality, which is unpredictable/hard to discover.

As a Brave user, I would prefer functional websites over incremental reduction in being tracked. Might it be reasonable to change the default value of this option, so that, by default, Brave will work for sites that use well-documented web APIs, but users can toggle to allow Brave to break some (in your interpretation, rarely used) functionality on behalf of extra privacy, for users that would trade consistent functionality for incremental privacy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed/invalid needs-more-info The report requires more detail before we can decide what to do with this issue.
Projects
None yet
Development

No branches or pull requests

9 participants