Brave Browser shields-up canvas app problems

Brave Browser shields-up canvas app problems

I originally wrote this as a response to a query around Konva, but it is relevant to any use of the HTML5 canvas in pages viewed in the Brave browser with Shields up. In this post I thought I would investigate, try to explain what I found and suggest a work-around.

TLDR: Brave is a browser that offers browsing anonymity. One of the attacks against this is browser fingerprinting. Fingerprinting relies on the HTML5 canvas. Konva, like other libs (kineticjs, fabricjs...), is a wrapper for the HTML5 canvas. Brave messes with the canvas.getImageData() method. These libs rely on this standard method of the HTML canvas. This means features of the libs are unreliable when used via the Brave browser. The workaround is to detect when a user is browsing with Brave and ask them to switch off fingerprinting protection. That feels like a lame answer, but at time of writing this is the only solution.

Brave is an emerging Internet browser that Kinsta reports in Nov 2023 has a market share of 0.05%.

It boasts fast performance and importantly for us, it provides strong privacy and advertisement blocking. For privacy read the ability to browse anonymously. In the old days the main way to identify a specific user was via cookies. We can now switch cookies off for anonymity.

However, the thirst of the advertising industry, folks like Meta and Google who sell our identity for targeted advertising, and the more malicious secret services and hackers, have led to the creation of other ways to uniquely identify a browser and thus remove your anonymity.

One such technique is 'Fingerprinting', the Wikipedia explanation of this is

đź’ˇ
When a user visits a page, the fingerprinting script first draws text with the font and size of its choice and adds background colors (1). Next, the script calls Canvas API’s ToDataURL method to get the canvas pixel data in dataURL format (2), which is basically a Base64 encoded representation of the binary pixel data. Finally, the script takes the hash of the text-encoded pixel data (3), which serves as the fingerprint …

magine that Meta run that on FaceBook - they know your browser fingerprint. They know your name, location, gender, and age from back when you signed up. Now they can sell your fingerprint in segmented demographic lists to advertisers…you know the rest.

So, Brave stops the ability for fingerprinting by messing with the HTML5 canvas.getImagedata() method. It is important to stress that Konva and other libs wrap the HTML5 canvas object. The canvas object is a standard part of the HTML standard. The libs rely on the HTML5 canvas. It is not in the lib developers power to 'fix' the fingerprinting issue. In fighting fingerprinting, Brave breaks that standard.

So what, stopping fingerprinting sounds good to me?

I agree, but getImageData is likely to be important to many of the features and core functions of any canvas comparable lib. Even without libs I have written apps that have required me to use getImageData for image processing. So I would say that getimageData is a critical requirement for successful use of the HTML5 canvas.

Where does this leave us?

Brave's default configuration with Shields (a feature of Brave) has fingerprinting switched on. Fingerprinting can be switched off per domain. Therefore it is possible, using JavaScript, to detect the browser the user is viewing your pages with, alert them to the issue, and ask them to disable fingerprinting for the site. Something like this:

if (navigator.brave === true) {
  ...
  display your advise to the user about disabling fingerprinting in Brave....
  ...
}

Note: You would want to ensure that you are not using any trackers within your site, such as Google stats or equivalent, because they are most likely using or will use fingerprinting. It might cause some consternation if to use your app a user has to lose their anonymity.

Could Konva be changed to work around this issue?

I am not the author of Konva, but I spend a lot of time in its source code. Before I got involved in Konva I developed a technique for optimised hit testing - then I found Konva and found that this was already how Konva does it! Canvas is vector-based drawing and we can use mathematical techniques to perform hit testing. However, these become problematic when the shape has shadow, is concave, or is a path or an image. The approach Konva takes is, AFAIK, the most reliable, robust, and high performance.

An explainer about Konva and getImageData

The baseline we need to remember is that the image you see on an HTML5 canvas is just a simple image. It has no DOM, no object structure, it is a dumb image of dots.

Now think about hit-testing for the mouse on a canvas showing an image with some transparency. Let us assume that the use-case is that we only want to detect a hit when the mouse is over a non-transparent area of the image. How can we achieve that?

HTML5 Canvas can tell us the co-ordinates of the mouse. It can give us the array of dot-data in which we can find the dot at the mouse point. We can look at the color data in that dot. If the dot is not transparent we have a hit, and if it is transparent we have a miss.

All nice and simple - except that the part about getting the dot-data relies on getImageData, which is the canvas method that Brave obstructs. Unfortunately this example is precisely how all hit-testing in Konva operates.

What this means is that there is a fundamental clash between Brave + Shields and any app that uses the HTML5 canvas. Konva uses getImageData for hit testing and image processing operations. Other libs will definitely require this method at some point.

Summary

We've seen why fingerprinting avoidance is an issue for apps that use HTML5 canvas, including Konva. We've also seen that there's no simple workaround and the best solution is to detect Brave users and advise them about the issue and how to configure their browser to use our apps. Sadly, the answer feels sketchy, but it's all that we can do at the moment.

Thanks for reading.

VW. Nov 2023.

Image by Erik Mclean on Unsplash