In daily life, biometric technology has become the standard equipment of most smart phones. Most mobile phones have facial recognition, fingerprint recognition and other functions, and the current fingerprint recognition technology has been very mature. But today’s talk isn’t about fingerprint recognition in biometrics, it’s about browser fingerprints. So many people have a love-hate relationship with this technology. Why? Let’s take a closer look at browser fingerprints today.

What is a browser fingerprint

Browser fingerprint can track Web browsers through the configuration and setting information that the browser can see on the website. It is just like the fingerprint on our hands, with individual identification, but at present, the browser fingerprint identifies the browser.

Browser fingerprint identification information can be UA, time zone, geographic location, or the language used, etc. The information developed by the browser determines the accuracy of the browser fingerprint.

For websites, getting the browser fingerprint is not of real value, what is really valuable is the user information corresponding to the browser fingerprint. As a webmaster, collecting a user’s browser fingerprint and recording the user’s actions is a valuable activity, especially in situations where there is no user identity.

For example, in A video website, User A, who has not registered the website, likes to browse the videos of the second dimension and records them through the browser fingerprint, so he can directly push the video of the second dimension to the browser next time. Because now the Internet devices are mostly private, such a push way is easy to gain the goodwill of most users, so as to make them become users of the website.

The development of browser fingerprinting

The development of browser fingerprinting technology, like most technologies, does not happen overnight. The existing generations of browser fingerprinting technology are as follows:

  • The first generation is stateful, which mainly focuses on the user’s cookie and evercookie, and requires the user to log in to get effective information.
  • In the second generation, the concept of browser fingerprint was introduced. By continuously increasing the characteristic values of the browser, users could be more differentiated, such as UA, browser plug-in information, etc
  • The third generation is already focused on people. By collecting users’ behaviors and habits to establish eigenvalues or even models for users, real tracking technology can be realized. However, the current implementation is more complex and is still under exploration.

Browser fingerprint tracking is now in the 2.5 generation, because the problem of fingerprint recognition across browsers has not been solved.

Fingerprint acquisition

Entropy of information is the average amount of information contained in each received message. The higher the entropy, the more information can be transmitted, and the lower the entropy, the less information can be transmitted.

Browser fingerprint is a combination of the characteristic information of many browsers, and the information entropy of the characteristic value is also different. Therefore, fingerprint is also divided into basic fingerprint and advanced fingerprint.

Basic fingerprint

A basic fingerprint is a part that can be easily found and modified, such as an HTTP header.

{ "headers": { "Accept": "text/html,application/xhtml+xml,application/xml; Q = 0.9, image/webp image/apng, * / *; Q = 0.8, application/signed - exchange; v=b3", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh; Q = 0.9, en. Q = 0.8 ", "the Host" : "", "the Sec - Fetch - Mode" : "navigate", "the Sec - Fetch - Site" : "none", "the Sec - Fetch - User" : "?1", "Upgrade-Insecure-Requests": "1", "user-agent ": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"}}

In addition to HTTP fingerprints, there are other ways to obtain browser characteristics, such as:

  • UA per browser
  • The HTTP Accept header sent by the browser
  • The browser extensions/plug-ins installed in the browser, such as QuickTime, Flash, Java or Acrobat, and the versions of these plug-ins
  • Font installed on the computer.
  • Whether the browser executes JavaScript
  • Can browsers plant cookies and “super cookies”?
  • Whether the browser is set to “Do Not Track”
  • System platform (e.g. Win32, Linux x86)
  • System languages (e.g. CN, EN-US)
  • Whether the browser supports touch screens

After these values are obtained, some calculations can be performed to obtain the specific entropy of the browser fingerprint and the UUID of the browser.

Such information, like human weight, height and skin color, has a high probability of repetition and can only be used as an aid to identification, so we need more accurate fingerprints to determine uniqueness.

Senior fingerprint

Ordinary fingerprints are not enough to distinguish between unique individuals, where advanced fingerprints are needed to further narrow the scope and even generate a unique cross-browser identity.

Each information used in the production of fingerprints has the right to be divided into major and small parts, and the information with high entropy will have a greater weight.

In the paper “Cross-Browser Fingerprinting via OS and Hardware Level Features […], more detailed study of the various indicators of information entropy and stability.

It can be seen from this paper that the weight of time zone, screen resolution, color depth, Canvas and WebGL information entropy in the cross-browser fingerprint is relatively large. Here’s a look at what these advanced fingerprints contain.

Canvas prints

Canvas is a dynamic drawing tag in HTML5. You can also use it to generate or manipulate images. Even if Canvas is used to draw the same element, due to the differences in systems, font rendering engines, anti-aliasing, sub-pixel rendering and other algorithms, Canvas will convert the same text into pictures, and the results will be different.

The implementation code is roughly: render some text on the canvas, then use todataURL conversion, even if the private mode can be turned on to get the same value.

function getCanvasFingerprint () {    
    var canvas = document.createElement('canvas');    
    var context = canvas.getContext("2d");    
    context.font = "18pt Arial";    
    context.textBaseline = "top";    
    context.fillText("Hello, user.", 2, 2);    
    return canvas.toDataURL("image/jpeg");

The process is very simple, rendering text, todataURL is to export the content of the entire Canvas, get the value.

WebGL fingerprint

WebGL (Web Graphics Library) is a JavaScript API that renders high-performance interactive 3D and 2D graphics in any compatible Web browser without the need for plug-ins. WebGL does this by introducing an API that is very consistent with OpenGL ES 2.0, which can be used within HTML5 elements. This consistency enables the API to take advantage of the hardware graphics acceleration provided by the user’s device. WebGL websites can use WebGL to identify device fingerprints. Generally there are two ways to do fingerprint production:

WebGL Reports – The full WebGL browser report table is available and can be checked. In some cases, it is converted to a hash value for faster analysis.

WebGL Images – Hidden 3D images that are rendered and converted to hashes. Since the final result depends on the hardware device on which the calculation is performed, this method generates unique values for different combinations of the device and its drivers. This approach generates unique values for different device combinations and drivers.

The BrowserLeaks Test can be used to see what information a website can access through the API.

To generate WebGL fingerprints, you first need to draw a gradient object with shaders and convert the image to a Base64 string. You then enumerate all the WebGL extensions and functionality and add them to the Base64 string, resulting in a huge string that may be very unique on each device.

For example, the fingerprint2js library’s WebGL fingerprint production method:

Gl = getWebGlCanvas () if (! gl) { return null } var result = [] var vShaderTemplate = 'attribute vec2 attrVertex; varying vec2 varyinTexCoordinate; uniform vec2 uniformOffset; void main(){varyinTexCoordinate=attrVertex+uniformOffset; Gl_Position = vec4 (attrVertex, 0, 1); }' var fShaderTemplate = 'precision mediump float; varying vec2 varyinTexCoordinate; Void main () {gl_FragColor = vec4 (varyinTexCoordinate, 0, 1); }' var vertexPosBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, VertexposBuffer) var vertices = new Float32Array([-0.20, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) // Create and initialize the Buffer object's datastore. gl.bufferData(gl.ARRAY_BUFFER, vertices, Gl. Static_draw) VertexPosBuffer.itemSize = 3 VertexPosBuffer.numItems = 3 Var vShader = gl.createProgram() var vShader = gl.createShader(gl.vertex_shader) var vShader = gl.createShader(gl.vertex_shader Gl. ShaderSource (vShader, vShaderTemplate) // Set the shader code gl.pileshader (vShader) // Compile a shader, To be used by the WebGlProgram object var fShader = gl.createShader(gl.FRAGMENT_SHADER) gl.shaderSource(fShader, FShaderTemplate) gl.compileShader(fshader) // Add predefined vertex shader and fragment shader gl. AttachShader (program, vshader) gl.attachShader(program, Fshader) // Link WebGlProgram object gl.linkProgram(program) // Add the defined WebGlProgram object to the current render state gl.useProgram(program) program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') gl.enableVertexAttribArray(program.vertexPosArray) gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, ! 1, 0, 0) gl.uniform2f(program.offsetuniform, 1, 1) // Draw primitive gl.drawarRates (gl.triangle_strip, 0, 1) from vector array vertexPosBuffer.numItems) try { result.push(gl.canvas.toDataURL()) } catch (e) { /* .toDataURL may be absent or broken (blocked by extension) */ }

How to prevent “user fingerprints” from being generated

As mentioned at the beginning of this article, many people have a love-hate relationship with the browser technology. That’s because a host of websites use various technologies to “generate” user fingerprints in order to give their users more accurate recommendations and to match their browsing habits. While users enjoy the convenience brought by technology, they will inevitably feel anxious and uneasy about “privacy leakage”. So how do we prevent “user fingerprints” being generated?

Confusing Canvas Fingerprint

We have learned how to obtain Canvas fingerprint, so how to prevent it from being acquired by malicious intent? To obfuscate a Canvas fingerprint, all you need to do is tamper with the results from toDataURL.

TodataURL () exports the contents of the entire Canvas. We need to modify part of the contents of Canvas. At this time, we can copy the pixel data of the specified rectangle on the Canvas through getImageData(), and then put the image data back through putimageData (). Then I use todataURL () to export a different image.

CanvasRenderingContext2D. GetImageData () returns a ImageData object, used to describe the Canvas area implied pixel data. This region is represented by a rectangle with a starting point of (sx, sy), width of sw, and height of sh.

The ImageData interface describes an area of implicit pixel data for the <Canvas> element, which can be constructed by the imageData () method, or by the creation method of the CanvasRenderingContext2D object held together by Canvas: CreateImageData () and getImageData ().

The ImageData object stores the actual pixel data of the Canvas object. It contains several read-only properties:

  • Width of the image in pixels
  • The height of the image, in pixels
  • data

Uint8ClampedArray – A one-bit array of type Uint8ClampedArray containing RGBA integer data in the range 0 to 255. It can be treated as the initial pixel data, with four 1 Bytes per pixel (in order of red, green, blue, alpha), each color represented by a number between 0 and 255. Each part is assigned to a contiguous index within an array, the red part of the first pixel in the upper left corner, at bit 0 of the array index. Pixels are processed from left to right and top to bottom, traversed through the array.

Unit8ClamPedarray contains height width of 4 bytes with index values from 0 to (WH4)-1.

For example, to read the blue part of the pixel in line 50, column 200 of the image, then:

const blueComponent = imageData[50*(imageData.width * 4) + 200*4 + 2]

Here’s how to obfuscate Canvas Fingerprints:

const toBlob = HTMLCanvasElement.prototype.toBlob; const toDataURL = HTMLCanvasElement.prototype.toDataURL; HTMLCanvasElement.prototype.manipulate = function() { const {width, height} = this; // Get CanvasRenderingContext2D const context = this.getContext('2d'); const shift = { 'r': Math.floor(Math.random() * 10) - 5, 'g': Math.floor(Math.random() * 10) - 5, 'b': Math.floor(Math.random() * 10) - 5 }; const matt = context.getImageData(0, 0, width, height); // Random changes are made to the r, g, b values of each pixel in the imageData generated by getImageData to generate a unique image. for (let i = 0; i < height; i += Math.max(1, parseInt(height / 10))) { for (let j = 0; j < width; j += Math.max(1, parseInt(width / 10))) { const n = ((i * (width * 4)) + (j * 4));[n + 0] =[n + 0] + shift.r; // add[n + 1] =[n + 1] + shift.g;[n + 2] =[n + 2] + shift.b; } } context.putImageData(matt, 0, 0); / / back to back. / / modify the prototype toBlob Object. DefineProperty (HTMLCanvasElement. Prototype, 'toBlob' {value: function() { if ( === 'true') { try { this.manipulate(); // ImageData} catch(e) {console.warn(' Manipulation failed', e); } } return toBlob.apply(this, arguments); }}); / / modify the prototype. ToDataURL Object. DefineProperty (HTMLCanvasElement. Prototype, 'toDataURL, {value: function() { if ( === 'true') { try { this.manipulate(); // ImageData} catch(e) {console.warn(' Manipulation failed', e); } } return toDataURL.apply(this, arguments); }});

Confusing other fingerprints

The idea of confusing Canvas fingerprint is the same as that of confusing Canvas fingerprint. Both are methods to change the prototype of the acquired object.

The confused time zone, for example, is to change the Date. The prototype. GetTimezoneOffset return values.

Ambiguity resolution is change the documentElement. ClientHeight documentElement. ClientWidth

Confusing WebGL requires changing the WebGLBufferData getParameter method, and so on.

Of course, there are some simple ways to prevent user fingerprints from being generated. For example, we can execute a JS code before the page loads through the browser’s extensions (Canvas Blocker, WebGL Fingerprint Defender, Fingerprint Spoofing, etc.). To protect our privacy information, change or rewrite various functions of JS to prevent websites from obtaining various information, or return a fake data.

Recommended reading

Go-Zero: Out of the box microservices framework

Say goodbye to DNS hijack, read DOH