Guide de défense contre l'empreinte numérique du navigateur : du Canvas Fingerprinting aux stratégies anti-pistage axées sur la confidentialité
Empreinte numérique du navigateur : pistage sans cookies
Même avec les cookies désactivés et le mode navigation privée activé, les sites web peuvent vous identifier de manière unique grâce à l'empreinte numérique du navigateur — avec un taux de précision allant jusqu'à 99,1 %.
| Type d'empreinte | Stabilité | Unicité | Difficulté de défense |
|---|---|---|---|
| User-Agent | Faible (change avec les mises à jour) | Moyenne | Faible |
| Canvas | Élevée | Élevée | Moyenne |
| WebGL | Élevée | Élevée | Moyenne |
| AudioContext | Élevée | Moyenne | Moyenne |
| Énumération des polices | Élevée | Élevée | Élevée |
| Résolution d'écran | Élevée | Moyenne | Faible |
| Fuseau horaire/Langue | Élevée | Faible | Faible |
1. Empreinte Canvas
Fonctionnement
Différents GPU, pilotes et algorithmes d'anticrénelage sur différents appareils produisent des différences subtiles dans la même sortie de rendu Canvas :
function getCanvasFingerprint() {
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 50;
const ctx = canvas.getContext('2d');
// Rendre du texte et des formes
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#f60';
ctx.fillRect(125, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.fillText('Hello, world! 🌍', 2, 15);
ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
ctx.fillText('Hello, world! 🌍', 4, 17);
// Extraire les données de pixels et hacher
const data = canvas.toDataURL();
return hash(data); // ex., "a1b2c3d4..."
}
Méthodes de défense
Méthode 1 : Injecter du bruit
// Remplacer toDataURL pour ajouter un bruit aléatoire subtil
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function (...args) {
const ctx = this.getContext('2d');
if (ctx) {
// Ajouter des pixels aléatoires à des positions discretes
const imageData = ctx.getImageData(0, 0, this.width, this.height);
const noise = Math.random() * 0.01;
imageData.data[0] = Math.min(255, imageData.data[0] + noise);
ctx.putImageData(imageData, 0, 0);
}
return originalToDataURL.apply(this, args);
};
Méthode 2 : Retourner des valeurs fixes
// Tous les canvas renvoient la même image vide
HTMLCanvasElement.prototype.toDataURL = function () {
return 'data:image/png;base64,...'; // Image vide fixe
};
2. Empreinte WebGL
Fonctionnement
WebGL expose les informations du rendeur et du fabricant du GPU, et différents GPU produisent différents résultats de rendu :
function getWebGLFingerprint() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
// Rendre une scène de test
// ... Différents GPU produisent différents résultats de pixels
return { vendor, renderer, renderHash };
}
Informations couramment divulguées
| Information | Exemple |
|---|---|
| Fabricant du GPU | "NVIDIA Corporation", "Intel", "AMD" |
| Rendeur du GPU | "GeForce RTX 4090", "Apple M2" |
| Taille maximale de texture | 16384, 8192 |
| Attributs maximaux de sommet | 16 |
| Liste des extensions prises en charge | 30+ noms d'extensions |
Méthode de défense
// Masquer les informations du GPU
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function (param) {
if (param === 37445) return 'Intel Inc.'; // UNMASKED_VENDOR
if (param === 37446) return 'Intel Iris'; // UNMASKED_RENDERER
return getParameter.call(this, param);
};
3. Empreinte AudioContext
Fonctionnement
Les unités de traitement audio (DSP) de différents appareils produisent des différences subtiles lors du traitement du même signal :
function getAudioFingerprint() {
const context = new OfflineAudioContext(1, 44100, 44100);
const oscillator = context.createOscillator();
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(10000, context.currentTime);
const compressor = context.createDynamicsCompressor();
compressor.threshold.setValueAtTime(-50, context.currentTime);
compressor.knee.setValueAtTime(40, context.currentTime);
compressor.ratio.setValueAtTime(12, context.currentTime);
oscillator.connect(compressor);
compressor.connect(context.destination);
oscillator.start(0);
return context.startRendering().then(buffer => {
const data = buffer.getChannelData(0);
return hash(data.slice(4500, 5000));
});
}
Méthode de défense
// Ajouter du bruit à la sortie AudioContext
const originalStartRendering = OfflineAudioContext.prototype.startRendering;
OfflineAudioContext.prototype.startRendering = function () {
return originalStartRendering.call(this).then(buffer => {
const data = buffer.getChannelData(0);
for (let i = 0; i < data.length; i++) {
data[i] += (Math.random() - 0.5) * 1e-7;
}
return buffer;
});
};
4. Empreinte par énumération des polices
Fonctionnement
En mesurant la largeur de rendu de différents noms de polices, on peut déterminer quelles polices sont installées sur le système de l'utilisateur :
function detectFonts() {
const testFonts = [
'Arial', 'Helvetica', 'Times New Roman',
'Courier', 'Verdana', 'Georgia',
'Comic Sans MS', 'Impact', 'Tahoma',
'Microsoft YaHei', 'PingFang SC',
];
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const baseFonts = ['monospace', 'serif', 'sans-serif'];
const results = {};
for (const font of testFonts) {
for (const base of baseFonts) {
ctx.font = `72px ${base}`;
const baseWidth = ctx.measureText('mmmmmmmmll').width;
ctx.font = `72px "${font}", ${base}`;
const testWidth = ctx.measureText('mmmmmmmmll').width;
if (baseWidth !== testWidth) {
results[font] = true;
break;
}
}
}
return results;
}
Méthodes de défense
L'énumération des polices est la plus difficile à défendre car elle exploite les capacités normales de rendu de texte du navigateur. Stratégies clés :
- Limiter le chargement des polices : N'autoriser que les polices système
- CSS font-display : block : Retarder les polices non essentielles
- Paramètres de confidentialité du navigateur :
privacy.resistFingerprintingde Firefox
5. Analyse complète de l'entropie de l'empreinte
| Dimension d'information | Entropie (bits) | Unicité cumulative |
|---|---|---|
| User-Agent | ~10 | 2^10 = 1 024 |
| Résolution d'écran | ~5 | 2^15 |
| Fuseau horaire | ~5 | 2^20 |
| Polices installées | ~15 | 2^35 |
| Canvas | ~15 | 2^50 |
| WebGL | ~10 | 2^60 |
| AudioContext | ~5 | 2^65 |
2^65 ≈ 3,7 × 10^19, suffisant pour identifier de manière unique chaque appareil sur Terre.
6. Architecture d'application axée sur la confidentialité
Stratégie de confidentialité de ToolsKu
Fichiers utilisateur → Traitement local dans le navigateur → Téléchargement direct du résultat
↑
Sans transit par serveur
Sans stockage de données
Sans cookies de pistage
Sans collecte d'empreinte numérique du navigateur
Liste de contrôle d'implémentation
| Stratégie | Implémentation | Priorité |
|---|---|---|
| Pas de pistage tiers | Supprimer les scripts comme Google Analytics | P0 |
| CSP restreint les ressources externes | default-src 'self' |
P0 |
| Aucun cookie défini | Le site statique n'a pas besoin de cookies | P0 |
| Referrer-Policy | strict-origin-when-cross-origin |
P1 |
| Permissions-Policy | Restreindre l'accès aux API | P1 |
| Déclaration de confidentialité | Divulguer clairement le traitement des données | P1 |
| Architecture de traitement local | Tous les calculs effectués dans le navigateur | P0 |
Configuration des en-têtes de sécurité HTTP
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
7. Testez votre propre empreinte
Nous recommandons d'utiliser les outils suivants pour tester l'unicité de l'empreinte numérique de votre navigateur :
- AmIUnique (amiunique.org) : Détection complète d'empreinte
- BrowserLeaks (browserleaks.com) : Analyse détaillée de Canvas/WebGL/Audio
- FingerprintJS (fingerprintjs.com) : Démo de la bibliothèque de fingerprinting open source
Conseils pour réduire votre empreinte :
- Utilisez Firefox +
privacy.resistFingerprinting = true - Utilisez Tor Browser (empreinte uniforme)
- Utilisez des extensions de confidentialité (Privacy Badger, uBlock Origin)
- Évitez d'installer des polices rares
- Utilisez des résolutions et des ratios de mise à l'échelle standard
Essayez ces outils exécutés localement dans le navigateur — aucune inscription requise →