Farbling-based wrappers to hinder browser fingerprinting

Browser fingerprinting is a more and more popular technique used to identify browsers. The fingerprint is computed based on the results of JavaScript calls, the content of HTTP headers, hardware characteristics, underlying operating system and other software information. Consequently, browser fingerprints are used for cross-domain tracking. However, users cannot clear their browser fingerprint as it is not stored on the client-side. It is also challenging to determine whether a browser is being fingerprinted.

Another issue that hinders fingerprinting protection is the ever-changing variety of supported APIs. Browsers implement new APIs over time, and existing APIs change. Consequently, it is necessary to continuously monitor the APIs being used for fingerprinting purposes to block fingerprinting attempts.

Due to fingerprinting scripts being more prevalent, various web browsers - for example, Tor, Brave, and Firefox - started implementing fingerprinting protection to protect users and their privacy.

This post contains:

Brave fingerprinting protection

Why is Brave's Farbling special? Until recently, Tor browser had the most robust defence against fingerprinting. It (1) implemented modifications in various APIs, (2) blocks some other APIs, (3) runs in a window of predefined size, etc. to ensure all users have the same fingerprint. This approach is very effective at producing uniform fingerprint for all users, which makes it difficult for fingerprinters to differentiate between browsers. Still, such fingerprint is also brittle -- minor changes like resizing the window could cause the browser to have a unique fingerprint. Hence, users need to follow inconvenient steps to keep their fingerprint uniform.

With all this in mind, Brave software decided to improve their fingerprinting protection. They proposed new fingerprinting protection, Farbling, arguing that it is (almost) impossible to produce uniform fingerprint without compromising user experience. Their countermeasures involve randomising values based on previous research papers PriVaricator and FPRandom Both papers have shown promising results, and Brave has perfected this approach, creating effective defence while retaining almost full user experience. Farbling is a comprehensive collection of modifications that aim at producing a unique fingerprint on every domain and in every session.

How does farbling work?

Farbling uses generated session and eTLD+1 keys to deterministically change outputs of certain APIs commonly used for browser fingerprinting. These little lies result in different websites calculating different fingerprints. Moreover, a previously visited website calculates a different fingerprint in a new browsing session.

Farbling implementation is publicly available on Github issue with discussions on design decisions, future plans and possible changes in a separate issue.

Farbling operates on three levels: 1. Off - countermeasures are not active 2. Balanced - various APIs have modified values based on domain/session keys 3. Maximum - various APIs values replaced by randomised values based on domain/session keys

Now, what changes did actually Brave implement to specific APIs?

Canvas

Canvas modifications are tracked in a separate issue. Both balanced and maximum approach modify API calls CanvasRendering2dContext.getImageData, HTMLCanvasElement.toDataURL, HTMLCanvasElement.toBlob, and OffscreenCanvas.convertToBlob. A Filter function changes values of certain pixels chosen based on session/domain keys, resulting in a unique canvas fingerprint. On maximum level, methods CanvasRenderingContext2D.isPointInPath and CanvasRenderingContext2D.isPointInStroke always return false.

WebGL

Modifications for both WebGL and WebGL2 are described in issues webgl , webgl2. On balanced level WebGLRenderingContext.getParameter and other methods return slightly modified values. WebGLRenderingContext.readPixels is modified similarly to canvas methods. On maximum level, WebGLRenderingContext.getParameter returns random strings for unmasked vendor and renderer, bottom values for other arguments. Other modified calls return bottom values. All modifications can be found in the issues mentioned above or directly in the code.

Web Audio

The issue modifies several endpoints of AnalyserNode and AudioBuffer APIs used for audio data handling are modified. On the balanced level, the amplitude of returned audio data is slightly changed based on the domain key. However, data are replaced by white noise generated from domain hash on the maximum level, so there is no relation with original data.

Plugins

Currently, navigator.plugins and navigator.mimeTypes are modified on balanced level to return an array with altered plugins and two fake plugins. On maximum level, the returned array contains only two fake plugins. See issue1 and issue2 for more details.

User agent

Brave employs the default Chrome UA and the newest OS version as the user agent string. Also, a random number of blank spaces (up to 5) appended to the end of the user agent string. For more details, see the GitHub issue.

EnumerateDevices

This API is used to list I/O media devices like microphone or speakers. When fingerprinting protection is active, Brave returns a shuffled list of devices. For more details, see issue1 and issue2.

HardwareConcurrency

The number of logical processors returned by this interface is modified as follows -- on balanced level, a valid value between 2 and the true value, on maximum level, a valid value between 2 and 8. See the GitHub issue for more details.

Porting Farbling to JShelter

Our goal was to extend JShelter anti-fingerprinting protections with similar measures to those available in Brave's Farbling. We decided to implement Brave Farbling with minor tweaks. As Brave is an open-source project based on Chromium, core changes are available in the public repository. Furthermore, as Brave is licensed under MPL 2.0 license, its countermeasures can be ported to JShelter. Similarly to Brave, JShelter utilises session and domain hashes (currently, we use a different domain hash based on origin, however, we consider switching to the eTLD+1 approach used by Brave). Nevertheless, we ported only those changes that an extension can reasonably apply. So we do not plan to change system fonts as the true set of fonts can leak in several ways (e.g., CSS, canvas). We will keep a close eye on anti-fingerprining techniquest applied by Brave in the future.

Former JShelter defences were left as an option so user can choose which protection they want. For example, for Canvas API, JShelter retains the old defence that returns a white image, but it is also possible to use Farbling and slightly modify the image.

CanvasRenderingContext2D.isPointInPath and CanvasRenderingContext2D.isPointInStroke are modified to return false with 5% probability, returning false to every call seems to be easily identifiable and it limits the usablity of the calls.

WebGL, Web audio, plugins, hardwareConcurrency and deviceMemory have been changed accordingly to Brave. API enumerateDevices has the same functionality as in Brave. In addition, we add fake devices to the list. User agent wasn't modified because it can cause compatibility issues as we support multiple browsers. Adding empty spaces at the end of UAS seems to be quite a weak countermeasure. We will continue to watch changes in the user agent and may implement some defence in future, although it looks like a better solution is on the way.

JShelter 0.5 changes the default level -- level 2 to apply the farbling-based defence for all covered APIs, and it will be very similar to the balanced level of Brave. Level 3 is redesigned to partly apply new and partly old countermeasures to provide as little information as possible. Please report websites that does not work correctly with Farbling.

During the examination of the ported code, we identified and reported an issue in the original Brave implementation. The issue was acknowledged and fixed by Brave. This is the beauty of the free software: several projects can benefit from the same code-base and mutualy improve the quality.

Conclusion

Farbling-based wrappers produce very similar outputs to Brave. So with JShelter, Farbling-like capabilities are available in multiple browsers. Nevertheless, keep in mind that the best anti-fingerprinting techniques are still a research question, fingerprinting techniques are deployed for security reasons (and farbling-like anti-fingerprinting masking may complicate some log in processes), so it is not completely clear what defences are the best and the choice of the defences also depends on specific use cases. We will investigate fingerprinting scripts further during the future work on this project.