You have been fingerprinted! Now I show you some exemples about how to do it

There are many ways to fingerprint the navigation of a user, and depending on the intentions that we have these can be more or less intrusive.

In this post we are going to portray a little bit the “basic” techniques that we can employ simply using what JavaScript provides us to obtain the most identifiable information of that particular navigation.

Perhaps the first data that someone would think of would be the classic ones: the IP address, the “User-Agent” of the browser. Simple data that are not only stored in our browser but also travel through the requests it makes. It seems simple from a backend to request both the client address and, in general, the headers that it includes. And it is more or less useful, but, the growing popularity of technologies such as VPN, as well as, browser extensions that change the headers with which it communicates are going to pose us problems. (If I am aware that I am going to talk about JavaScript, and that there are extensions that block JS, from the Server-Side you can do things but come on, those people do not deserve to be in this world).

I’m sure many are familiar with the web pages that actually fingerprint your browser and tell you how “common” or less common that information becomes in terms of the profile that can be generated about your specific browsing.
A common example is Cover Your Tracks from EFF

With the navigator.userAgent object it is very easy to obtain from JS this object from the browser, I leave you here a test:


If we prefer to focus on the browser, and on what we can obtain from it that identifies it more reliably, we find an assortment of options that will allow us to obtain concrete information on who is browsing. Therefore, we are going to focus on the fingerprint that can be performed from the “Client-Side”, we will go deeper later on how to treat this data from a server.

There are other browser objects that allow us to identify the browser technology, not only the “user-agent” used as a header in the HTTP protocol. Within the “navigator” object, some object options such as navigator.appVersion or navigator.vendor can provide equally useful information that is not usually edited.



However there are more things that detail the web browser specifically, among them we can find very funny and classic things. Perhaps one of the simplest is the ```navigator.platform`` which identifies the operating system on which the browser runs. This is still a classic object within what JavaScrip Vanila provides us, but it identifies data more related to the user than to the navigation as such.


If we already get a little bit bastards with the topic, although we have in mind that in the content of this post we are only going to talk about what JavaScript provides us natively (we will enter in libraries, and other superfluous). Perhaps one of the first points that is commonly used to perform a concrete fingerprint is everything that has to do with “graphics”, from simple things like getting the screen resolution (salute to the famous Tor Browser popup that mentioned this). The browser object screen.width and screen.height will provide that information.


Well, at this point, we could spend several posts just telling each and every one of the resources provided by JavaScript and how useful they are to identify the browser.

Two details to keep in mind, there are fields, such as the main language of the browser, or specific things like whether or not it has flags such as “onLine” “doNotTrack” or “cookieEnabled” that are interesting because they are usually kept at their default values. Following is an example of an object that collects this information that we have been talking about so far.

On the other hand, it is interesting to include in our fingerprint a timestamp that provides us with the date and time of the “click” in order to later process this data.

1
2
3
4
5
6
7
8
9
10
11
12
let data = {
browserPlatform: navigator.platform,
browserVendor: navigator.vendor,
browserLanguage: navigator.language, //*
browserVersion: navigator.appVersion,
cookiesEnabled: navigator.cookieEnabled, //*
doNotTrack: navigator.doNotTrack, //*
online: navigator.onLine, //*
screenResolution: screen.width + "x" + screen.height,
ts: new Date().getTime()
};
//These fields are usually deactivated, if the user activates them manually, it is a very direct way to identify you.

May this is not enough, although so far we have dealt with those JavaScript resources that do not give many problems, those that natively we know that the default settings of most browsers will be satisfactory. From here, we are going to go a little deeper, not too much, we continue within what natively provides us the browser. Since some time ago, WEBGL is a more than popular technology used for the rendering of 3D objects in the browser, and therefore, this is something that makes our graphics card, which is identified as the “RENDERED” that uses WebGL, for this I leave a simple code sample that creates an empty WebGL Canvas from which this information is obtained (Thanks to ChatGPT for saving us time of life).

1
2
3
4
5
6
7
8
9
10
11
function getGpuModel() {
var canvas = document.createElement("canvas");
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");

if (gl) {
var gpuModel = gl.getParameter(gl.RENDERER);
return gpuModel;
}

return "WebGL no está soportado por el navegador";
}

You can use this test I leave here as in the other cases, it literally calls the function I showed before. However, it is possible that your browser, for whatever reason, or that you yourself are aware of, does not have WebGL enabled, in which case you will burn in hell.


Finally, to start to finish this first part on browser fingerprinting, which is starting to get long, as we said before, there is much of what JavaScript can provide us to identify the browser, its configuration, the computer where it runs or things that identify more the user himself. Other useful fields are, for example, the information of the hardware to which the browser accesses, easily obtainable by means of the object navigator.hardwareConcurrency. I leave here the classic example in this post:


And a last interesting resource, which is also rarely changed, and if it does, is a fairly direct way to identify a user or failing that, the type of browser itself, the font, and more specifically the size of this. natively JavaScript has the option getComputedStyle that returns an object with this information to which we can easily access.

Each browser brings its font and size by default, in fact it is a way to differentiate browsers from each other, if the previous options do not really work (for whatever reason). But also if this is edited, we can identify that this person uses that browser with the font changed, case that although it is not common, it is interesting to take into account.

1
getComputedStyle(document.documentElement).fontSize

And so far this little introduction to fingerprinting, this can be very broad depending on the intentions with which we want to perform this identification, also say that in many cases we will determine which data to use or not if we want a more accurate identification of the user even if this employs several browsers or technologies such as those mentioned above, we will delve into this later. It is also clear that browsers such as TorBrowser, LinkedSphere, FraudFox among others will give us problems and casuisticas with which we will have to fight. Practically every case will be different, so we will have to have the precision of someone peeing on a cliff if we want to have a fingerprint that no one can escape from.

Ah, before we go, this blog uses several of these techniques for researching purposes only, so thank you for your data, but don’t worry, I will keep them with much affection. :D

A hug for all hackers ^^