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 :

  1. Limiter le chargement des polices : N'autoriser que les polices système
  2. CSS font-display : block : Retarder les polices non essentielles
  3. Paramètres de confidentialité du navigateur : privacy.resistFingerprinting de 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 :

  1. Utilisez Firefox + privacy.resistFingerprinting = true
  2. Utilisez Tor Browser (empreinte uniforme)
  3. Utilisez des extensions de confidentialité (Privacy Badger, uBlock Origin)
  4. Évitez d'installer des polices rares
  5. 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 →

#浏览器指纹#隐私安全#Canvas#WebGL#反追踪