Aperçu
L'empreinte Canvas exploite les différences subtiles dans la façon dont le matériel et le logiciel rendent les graphiques. Ces différences proviennent de :
- Modèle GPU et version du pilote
- Rendu des polices du système d'exploitation (anti-aliasing, hinting, rendu subpixel)
- Moteur de rendu du navigateur
- Polices système installées
Empreinte Canvas
Mécanisme
- Le site dessine des formes et du texte sur un élément
<canvas>HTML5 - Appelle
canvas.toDataURL()pour extraire les données de pixels en base64 - Hache le résultat (MD5, SHA-1, ou hachage personnalisé)
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
ctx.font = '14px Arial'
ctx.fillStyle = '#f60'
ctx.fillRect(125, 1, 62, 20)
ctx.fillStyle = '#069'
ctx.fillText('BrowserLeaks,com <canvas> 1.0', 2, 15)
const fingerprint = canvas.toDataURL()
const hash = md5(fingerprint) // unique par périphérique
Sources d'Entropie
| Source | Variabilité |
|---|---|
| Rendu des polices (anti-aliasing, hinting) | Élevée |
| Ordre de rendu subpixel (RVB vs BVR) | Moyenne |
| Rastérisation GPU des formes | Moyenne |
| Conversion d'espace colorimétrique | Faible |
Empreinte WebGL
Mécanisme
WebGL expose le GPU directement via :
const gl = canvas.getContext('webgl')
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info')
const renderer = debugInfo.UNMASKED_RENDERER_WEBGL
// ex., "NVIDIA GeForce RTX 3080/PCIe/SSE2"
const vendor = debugInfo.UNMASKED_VENDOR_WEBGL
// ex., "NVIDIA Corporation"
De plus, le rendu de scènes 3D produit une sortie de pixels spécifique au matériel.
Signaux
UNMASKED_RENDERER_WEBGL— modèle GPU exactUNMASKED_VENDOR_WEBGL— fabricant GPU- Précision des shaders WebGL
MAX_TEXTURE_SIZE,MAX_VERTEX_ATTRIBS, etc.- Rendu de scène 3D (hachage des pixels)
Empreinte WebGPU
WebGPU (le successeur de WebGL) expose des informations encore plus granulaires :
const adapter = await navigator.gpu.requestAdapter()
const info = await adapter.requestAdapterInfo()
// { vendor: "nvidia", architecture: "ampere", device: "..." }
Signaux
adapterInfo.vendoradapterInfo.architectureadapterInfo.device- Ensemble de fonctionnalités (quelles fonctionnalités GPU sont supportées)
Pourquoi l'Usurpation au Niveau Proxy est Difficile
Le rendu Canvas/WebGL/WebGPU s'effectue sur le GPU local. Le proxy ne voit que le trafic réseau. Au moment où les données atteignent le proxy, le rendu est déjà terminé.
Approches d'atténuation possibles :
Bloquer l'API : Faire en sorte que WebGL retourne null, canvas génère une erreur. Problème : détectable comme signal ("WebGL bloqué" est lui-même un trait d'empreinte).
-
Injecter du bruit JS : CanvasBlocker (Firefox) randomise la sortie canvas en injectant un pixel aléatoire avant
toDataURL(). Problème : si le site lit le canvas 3 fois et obtient 3 hachages différents, il détecte la manipulation. Nécessite également un bruit cohérent en fréquence. -
Surcharge ImageData via Proxy : Surcharger
CanvasRenderingContext2D.prototype.getImageDatavia JS injecté pour retourner des données génériques. Problème : fonctionne seulement surgetImageData, pastoDataURL. Chemins multiples pour extraire les pixels.
Rendu GPU logiciel (SwiftShader/Lavapipe) : Remplacer le rendu GPU par un rendu déterministe basé sur CPU. Problème : coût de performance massif, pas d'accélération 3D.
Formules
Entropie de l'Empreinte Canvas
Où est la probabilité d'un hachage donné sur différents appareils.
Entropie estimée : ~5-7 bits (peut distinguer ~32-128 appareils).
Probabilité d'Unicité
Où est la taille de la population et est le nombre de sorties canvas distinctes dans l'échantillon.
Conclusions
- L'empreinte Canvas/WebGL ne peut pas être entièrement usurpée au niveau proxy
- L'injection de bruit via JS est une atténuation partielle mais détectable
- Bloquer ces API est détectable et devient un signal en soi
- La seule solution quasi-complète est l'approche de Tor Browser (normaliser tous les utilisateurs vers une sortie identique)
- Pour Obscura : la meilleure approche est du JS injecté qui ajoute un bruit cohérent + bloque
WEBGL_debug_renderer_info