WebGL Pixel Hash : comment les shaders GLSL identifient votre GPU
Navigateur & Appareil

WebGL Pixel Hash : comment les shaders GLSL identifient votre GPU

Le WebGL pixel hash fingerprinting rend un shader GLSL invisible et hache les pixels résultants — exploitant les micro-différences de virgule flottante GPU persistant à travers navigateurs et VPN.

8 min de lecture·

Le WebGL pixel hash fingerprinting rend une scène de test invisible à l'aide d'un shader GLSL et lit les pixels résultants avec gl.readPixels() — exploitant le fait que chaque GPU calcule l'arithmétique en virgule flottante légèrement différemment, produisant un hash stable qui identifie votre matériel à travers tous les navigateurs, survit à la suppression des cookies, et ne peut pas être masqué par un VPN. Vérifiez votre propre WebGL pixel hash sur whatsmy.fyi.

En résumé

Un programme de shader GLSL est compilé et exécuté sur votre GPU dans un canvas WebGL caché. Les valeurs de pixels rendus sont lues en retour et hachées en un identifiant compact. Parce que l'arrondi en virgule flottante dans les unités de shader GPU varie entre fabricants, architectures et versions de pilotes, le même shader produit des sorties de pixels subtilement différentes sur des matériels différents — même sur deux machines avec le même modèle GPU mais des pilotes différents. Cela rend le pixel hash plus précis que simplement lire la chaîne GPU renderer, qui ne révèle que le modèle matériel, pas le comportement exact au niveau du pilote.

Qu'est-ce que le WebGL pixel hash fingerprinting ?

Le WebGL pixel hash fingerprinting est une technique spécifique au sein de la famille plus large du WebGL fingerprinting qui cible la sortie computationnelle de votre GPU plutôt que ses métadonnées. Alors que lire la chaîne GPU renderer via WEBGL_debug_renderer_info indique le modèle GPU à un traceur, elle ne peut pas distinguer deux GPU identiques exécutant des versions de pilotes différentes. Le pixel hash comble cet écart.

La technique fonctionne parce que l' API WebGL donne à JavaScript un accès direct à l'exécution des shaders GPU. Un script de fingerprinting peut écrire un shader de fragment GLSL qui effectue des opérations mathématiques — fonctions trigonométriques, parties fractionnaires, bruit pseudo-aléatoire — et faire exécuter ces calculs par le GPU. Les valeurs de couleur résultantes écrites dans chaque pixel dépendent de la façon dont les unités en virgule flottante du GPU gèrent ces opérations en interne. Différentes architectures GPU accumulent les erreurs d'arrondi différemment, et différentes versions de pilotes sur le même GPU peuvent produire des sorties mesurables différentes.

C'est étroitement lié au canvas fingerprinting, qui lit également la sortie de pixels — mais le canvas fingerprinting cible le rendu de polices 2D et les différences d'anti-aliasing. Le WebGL pixel hashing cible directement l'arithmétique des shaders 3D du GPU, le rendant à la fois plus entropique et plus difficile à normaliser.

Comment fonctionne le WebGL pixel hash fingerprinting ?

L'ensemble du processus s'exécute en JavaScript, prend moins de 50 millisecondes et est totalement invisible pour l'utilisateur. Il se déroule en quatre étapes.

Étape 1 — Création d'un canvas WebGL caché

Le script crée un élément canvas hors-écran — jamais attaché au document — et obtient un contexte de rendu WebGL. La taille du canvas est typiquement petite (256×128 ou 512×256 pixels) pour maintenir une exécution rapide. Le canvas n'est jamais affiché.

Étape 2 — Compilation d'un shader conçu pour maximiser la variation

Un shader de fragment GLSL est écrit pour effectuer des opérations sensibles aux différences de précision en virgule flottante. Les shaders les plus efficaces combinent sin(), cos(), fract() et des multiplications de grands coefficients — parce que ces opérations accumulent des erreurs d'arrondi différemment selon les architectures GPU.

// Shader de fragment GLSL pour le fingerprinting par pixel hash
precision highp float;

void main() {
  float x = gl_FragCoord.x / 256.0;
  float y = gl_FragCoord.y / 128.0;

  // Ces combinaisons sin/fract amplifient les différences de virgule flottante GPU
  float r = fract(sin(x * 12.9898 + y * 78.233) * 43758.5453);
  float g = fract(sin(x * 93.989 + y * 17.211) * 43421.631);
  float b = fract(cos(x * 51.234 + y * 31.456) * 12345.678);

  gl_FragColor = vec4(r, g, b, 1.0);
}

Les grands multiplicateurs constants (43758.5453, 43421.631, 12345.678) signifient que de minuscules différences en virgule flottante dans les résultats intermédiaires sont amplifiées en différences de couleur visibles lorsque fract() les enroule. Deux GPU qui s'accordent à 14 décimales dans leur arithmétique intermédiaire produiront quand même des couleurs de pixels finales différentes.

Étape 3 — Lecture des pixels avec gl.readPixels()

Après l'exécution du shader, le script appelle gl.readPixels() pour transférer les données de pixels rendus de la mémoire GPU vers un Uint8Array JavaScript. Cela donne au script un accès direct aux valeurs RGBA de chaque pixel dans le canvas — le résultat numérique brut du calcul du shader GPU.

// JavaScript : compiler le shader, rendre, et extraire les pixels
const canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 128;
const gl = canvas.getContext('webgl');

// Compiler et lier les shaders vertex + fragment (abrégé)
const program = compilersAndLinkShaders(gl, vertexSrc, fragmentSrc);
gl.useProgram(program);

// Dessiner un triangle strip plein écran
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

// Lire les données de pixels depuis la mémoire GPU
const pixels = new Uint8Array(256 * 128 * 4); // largeur × hauteur × RGBA
gl.readPixels(0, 0, 256, 128, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

// Hacher le tampon de pixels → empreinte GPU stable
const hash = fnv1a(pixels); // ou MurmurHash, xxHash, etc.

Étape 4 — Hachage du tampon de pixels

Le tableau de pixels complet — 131 072 octets pour un canvas 256×128 — est haché en une valeur compacte. Les choix courants sont FNV-1a (rapide, non cryptographique), MurmurHash3 ou une somme numérique simple des octets de pixels échantillonnés. Le résultat est une courte chaîne hexadécimale représentant le comportement exact en virgule flottante des unités de shader GPU. Ce hash est stable à travers les redémarrages du navigateur, les sessions de navigation privée et les redémarrages de l'appareil. Il ne change que lorsque le pilote GPU est mis à jour ou que le matériel physique est remplacé.

Différences entre pixel hash GPU et chaîne renderer GPU

PropriétéChaîne GPU RendererWebGL Pixel Hash
Ce qu'il litNom de modèle GPU + chaîne vendeurSortie de calcul du shader
API utiliséeWEBGL_debug_renderer_infogl.readPixels()
Distingue même GPU, pilotes différents ?Non — même GPU donne toujours la même chaîneOui — les différences de pilotes changent la sortie de pixels
Bloqué par privacy.resistFingerprinting ?Oui — retourne un substitut génériquePartiellement — nécessite une normalisation supplémentaire
Nécessite une extension WebGL ?Oui — WEBGL_debug_renderer_infoNon — utilise le WebGL de base

Données d'unicité du WebGL pixel hash

RésultatValeurSource
Entropie de la sortie de rendu WebGL seule~5,7 bitsRecherche Fingerprint.com
Stabilité du pixel hash à travers les redémarrages de navigateurQuasi 100 % (change seulement avec mise à jour pilote)Cao et al., NDSS 2017
Cohérence inter-navigateurs sur le même matérielÉlevée — l'arithmétique matérielle est indépendante du navigateurCao et al., NDSS 2017
Identifiabilité combinée GPU renderer + vendeur + pixel hash< 0,01 % des visiteurs partagent le même tripletRecherche terrain Inria / KU Leuven
Support WebGL navigateur (Chrome, Edge, Safari, Firefox)95–99 %BrowserLeaks WebGL Test

Pourquoi le pixel hash persiste à travers les navigateurs

C'est la caractéristique qui rend le WebGL pixel hashing particulièrement précieux pour le pistage inter-navigateurs — un scénario que les systèmes basés sur les cookies ne peuvent fondamentalement pas adresser. Lorsque vous utilisez Chrome, Firefox et Edge sur la même machine, chaque navigateur maintient des jars de cookies et un stockage local complètement séparés. Mais tous les trois partagent le même GPU et le même pilote sous-jacents. Le shader GLSL est compilé indépendamment dans chaque navigateur, mais exécuté sur le même matériel — produisant une sortie de pixels identique (ou presque) sur tous.

Des recherches publiées au NDSS 2017 par Cao et al. ont démontré cette capacité de fingerprinting inter-navigateurs en utilisant exactement cette approche : la sortie de rendu GPU était utilisée pour lier des sessions de navigation à travers différentes installations de navigateurs sur le même appareil sans aucun état partagé entre eux.

RGPD et WebGL pixel hash fingerprinting

La CNIL a statué que le browser fingerprinting à des fins de pistage publicitaire requiert un consentement éclairé au sens du RGPD, même lorsqu'aucun cookie n'est déposé. Le WebGL pixel hash, en tant que technique de fingerprinting basée sur les caractéristiques matérielles du GPU, constitue un traitement de données personnelles soumis à cette exigence. Les exemptions d'intérêt légitime s'appliquent uniquement pour la détection de fraude et la sécurité informatique dans un cadre strictement défini.

Comment se protéger du WebGL pixel hash fingerprinting

  • Tor Browser (protection maximale) : Tor Browser désactive gl.readPixels() dans sa configuration par défaut, rendant impossible pour les scripts la lecture des données de pixels rendus. Il restreint également WebGL à un mode de capacité minimale.
  • Brave Browser (recommandé pour l'usage quotidien) : Le système Farbling de Brave injecte une petite valeur de bruit aléatoire par session dans la sortie de pixels WebGL. Le bruit est cohérent au sein d'une session (les applications WebGL fonctionnent correctement) mais change entre sessions et entre différents sites — rendant le pixel hash peu fiable comme identifiant de pistage.
  • Firefox avec privacy.resistFingerprinting : L'activation de ce paramètre dans about:config normalise la sortie WebGL dans Firefox. La protection est moins agressive que le Farbling de Brave mais ne nécessite pas de changer de navigateur.
  • Désactivation de WebGL dans Firefox : Définir webgl.disabled à true dans about:config empêche complètement le rendu WebGL. Cela élimine le signal de pixel hash mais casse également Google Maps 3D, les jeux en navigateur et certaines interfaces de visioconférence.
  • Les limites des VPN : Un VPN chiffre votre trafic réseau et change votre IP visible, mais n'a aucun effet sur l'exécution des shaders GPU. Vérifiez la protection IP de votre VPN sur whatsmy.fyi, mais comprenez qu'il ne traite aucun type de fingerprinting.

Foire aux questions

Quelle est la différence entre un WebGL pixel hash et une chaîne renderer WebGL ?

La chaîne renderer est une étiquette textuelle — par exemple "NVIDIA GeForce RTX 4080/PCIe/SSE2" — retournée par l'extension WEBGL_debug_renderer_info. Elle identifie votre modèle GPU mais est identique pour toutes les machines avec ce GPU exact. Le pixel hash est une empreinte numérique du calcul réel de votre GPU — produite en exécutant un shader de test et en lisant la sortie des pixels. Il capture les différences au niveau du pilote et du silicium qui le rendent unique même parmi des machines avec des modèles GPU identiques.

Le pixel hash fonctionne-t-il en navigation privée ?

Oui. La navigation privée empêche votre navigateur d'enregistrer les cookies, l'historique et les téléchargements sur disque — mais elle ne change pas votre matériel GPU ni votre pilote. Le pixel hash est généré entièrement à partir du calcul GPU et est identique en fenêtre normale et privée. Seuls les navigateurs avec protection active des empreintes (Brave, Firefox avec privacy.resistFingerprinting, Tor Browser) produisent une sortie différente.

Deux GPU différents peuvent-ils produire le même pixel hash ?

Oui, mais c'est statistiquement peu fréquent. Les GPU de différents fabricants (NVIDIA, AMD, Intel, Apple) ne produisent presque jamais le même hash parce que leurs architectures de shader gèrent les opérations en virgule flottante fondamentalement différemment. Les GPU dans la même famille de produits — deux RTX 3070 exécutant des pilotes identiques — produiront généralement le même hash, ce qui explique pourquoi le pixel hash est le plus puissant combiné avec la chaîne GPU renderer et d'autres signaux.

La mise à jour du pilote GPU change-t-elle le pixel hash ?

Parfois. Les mises à jour de pilotes modifient parfois le comportement en virgule flottante de l'exécution des shaders — particulièrement pour les fonctions trigonométriques sur les générations GPU plus anciennes. En pratique, les mises à jour majeures de pilotes changent occasionnellement le hash ; les mises à jour de stabilité mineures typiquement non.

Ce technique est-elle la même que dans le papier "Rendered Private" ?

Oui. Le papier USENIX Security 2019 "Rendered Private: Making GLSL Execution Uniform to Prevent WebGL-based Browser Fingerprinting" par Wu, Li, Cao et Wang traite directement le WebGL pixel hash fingerprinting. Leur mitigation proposée, UNIGL, réécrit le code source des shaders GLSL au niveau du navigateur pour rendre la sortie de rendu uniforme à travers différents matériels. À ce jour, UNIGL n'a pas été adopté par les navigateurs majeurs et reste un prototype de recherche.

Articles connexes

Vérifiez votre adresse IP, localisation et score de confidentialité — instantanément.

Zéro log. Zéro tracking. Zéro API externe.

Lancer la vérification →

Articles connexes

WebGL Pixel Hash : comment les shaders GLSL identifient votre GPU | whatsmy.fyi