1 points par GN⁺ 2024-03-11 | 1 commentaires | Partager sur WhatsApp
  • Safari 17 ajoute un bruit aléatoire à chaque échantillon de l’Audio API en navigation privée pour perturber l’empreinte audio, mais FingerprintJS y répond avec un nouvel algorithme d’empreinte qui réduit cet effet
  • L’ancienne méthode utilisait la somme de 500 échantillons audio comme identifiant, si bien que l’amplitude du bruit de Safari dépassait les écarts entre navigateurs et faisait perdre en stabilité
  • La nouvelle méthode crée en masse des copies bruitées d’un même échantillon audio et réduit les variations avec (min+max)/2 et un arrondi aux chiffres significatifs
  • En chaînant un OscillatorNode carré, un DynamicsCompressorNode et un BiquadFilterNode, FingerprintJS a accru les écarts entre navigateurs et porté l’écart minimal du 3396e échantillon à 0.0014%
  • Le nouvel algorithme a remplacé l’ancienne empreinte audio dans FingerprintJS à partir de la version 4.2.0 ; le temps de calcul augmente de 1,5 à 2 fois, mais reste court même sur des appareils peu puissants

Comment Safari 17 perturbe l’empreinte audio

  • L’empreinte audio consiste à rendre un signal audio avec l’Audio API du navigateur et OfflineAudioContext, puis à additionner les échantillons pour produire un nombre identifiant unique
  • Cet identifiant a l’avantage d’être stable, car il ne change pas quand on supprime les cookies ou qu’on passe en mode privé, mais son unicité reste limitée car de nombreux utilisateurs peuvent partager la même valeur
  • La protection avancée contre l’empreinte de Safari 17 est activée par défaut en navigation privée et désactivée en mode normal, sur desktop comme sur mobile
  • La protection affecte aussi les API Screen et Canvas, mais ici seul le cas de l’Audio API est traité
  • Quand la protection est active, Safari multiplie chaque échantillon audio par un bruit aléatoire distinct
    • Un échantillon bruité se situe entre sample*(1-magnitude) et sample*(1+magnitude)
    • La distribution est uniforme
    • Comme le développement de Safari continue, les détails d’implémentation peuvent évoluer avec le temps

Où le bruit est injecté dans l’Audio API

  • Safari applique ce bruit dans plusieurs interfaces permettant de lire le signal audio
  • Comme le bruit change à chaque application, l’empreinte audio varie à chaque calcul dans le mode privé de Safari 17
  • Sur Safari 17 d’un MacBook Air M1, l’empreinte fluctue entre 124.03516 et 124.04545, soit un écart d’environ 0.008%
  • Le plus petit écart observé entre anciennes empreintes audio de différents navigateurs n’était que de 0.0000023%, bien inférieur à la plage de bruit de Safari
  • Pour supprimer le bruit, il faudrait arrondir à environ un chiffre après la virgule, mais en conservant moins de 6 chiffres, il devient difficile de distinguer certains navigateurs, ce qui réduit l’unicité

Les 3 étapes du nouvel algorithme

  • Le nouvel algorithme d’empreinte audio de FingerprintJS suit trois étapes pour réduire le bruit ajouté par Safari
    • réduire la variance du bruit
    • augmenter la distance entre les identifiants numériques des navigateurs
    • supprimer le bruit résiduel par arrondi
  • L’ancienne empreinte audio étant la somme de 500 échantillons, le bruit uniforme appliqué à chaque échantillon produit au total un bruit proche d’une distribution normale
  • La moyenne d’une distribution normale doit être estimée à partir d’un grand nombre d’échantillons, alors que celle d’une distribution uniforme peut être estimée plus précisément avec moins d’échantillons via (min+max)/2
  • Dans le code expérimental, il fallait 524,288 échantillons pour la distribution normale au même niveau de précision, contre seulement 4,096 pour la distribution uniforme
  • La nouvelle méthode abandonne l’empreinte fondée sur une somme pour ne collecter qu’un seul échantillon audio, afin de traiter un bruit uniforme
  • Ce changement rend la nouvelle empreinte incompatible avec l’ancienne ; une approche séparée est nécessaire pour migrer sans perdre les identifiants de visiteurs

Créer des copies bruitées d’un même échantillon audio

  • Appeler plusieurs fois getChannelData sur une instance AudioBuffer ne fonctionne pas
    • le bruit n’est appliqué qu’une fois par instance AudioBuffer
    • getChannelData renvoie donc le même signal pour une même instance
  • Réexécuter tout le processus de génération du signal audio permettrait de créer de nombreuses instances AudioBuffer, mais c’est trop lent pour un calcul d’empreinte
    • pour 6,000 échantillons bruités, le meilleur temps observé sur un MacBook M1 était de 7 secondes
    • à 60,000, Safari ne terminait pas le traitement
  • Une meilleure solution consiste à créer une instance AudioBuffer qui répète le même signal audio
    • le premier signal audio est rendu sans appeler getChannelData
    • un second OfflineAudioContext, plus long, est créé en utilisant le signal d’origine comme AudioBufferSourceNode
    • loop, loopStart et loopEnd servent à répéter une partie du signal d’origine
    • Safari ajoute ensuite le bruit après la répétition, ce qui produit plusieurs copies du même échantillon audio avec des bruits différents
  • Cette méthode permet de produire le nombre nécessaire de copies bruitées avec seulement deux rendus audio
  • Le bruit ne disparaît pas complètement, mais sa variance devient plus faible que celle de l’échantillon d’origine
    • 8,192 copies : plage de 0.000387% sur 100 exécutions, 2.6ms sur un MacBook M1
    • 65,536 copies : 0.0000123%, 4.1ms
    • 262,144 copies : 0%, 7.5ms

Accentuer les écarts d’échantillons audio entre navigateurs

  • Réduire le nombre de copies améliore les performances mais augmente la variance des résultats ; pour compenser, FingerprintJS a modifié le signal de base afin d’amplifier les différences entre navigateurs
  • Après avoir testé plusieurs nœuds audio intégrés, la chaîne de génération de signal qui augmentait le plus les écarts entre navigateurs était la suivante
  • Le 3396e échantillon du signal audio présentait l’écart le plus élevé entre navigateurs, après comparaison de tous les échantillons sur plusieurs navigateurs
  • Dans l’échantillon de navigateurs retenu, le plus petit écart pour ce nouvel échantillon était de 0.0014%
    • supérieur au plus petit écart de l’ancienne empreinte, 0.0000023%
    • ce qui permet d’appliquer une suppression du bruit plus agressive et un arrondi plus grossier

Stabiliser l’empreinte par arrondi

  • Même avec une plage de bruit plus faible sur un seul échantillon, la valeur continue de fluctuer ; un arrondi reste donc nécessaire pour l’utiliser comme empreinte finale
  • Comme le bruit est appliqué relativement à la valeur de l’échantillon audio et non en valeur absolue, l’arrondi se fait sur les chiffres significatifs plutôt que sur les décimales
  • Cinq chiffres significatifs suffisaient pour distinguer les navigateurs testés, mais davantage de chiffres ont été conservés faute de visibilité sur l’ensemble des navigateurs et sur les évolutions futures
  • En mode privé sur Safari 17, le nombre de copies nécessaire pour stabiliser l’empreinte selon la précision d’arrondi était le suivant
    • 6 chiffres significatifs : 15,000, environ 3ms sur un Safari 17 déjà chaud sur MacBook M1
    • 7 chiffres significatifs avec arrondi du dernier chiffre au multiple de 5 : 30,000, 4ms
    • 7 chiffres significatifs avec arrondi du dernier chiffre à l’entier pair le plus proche : 70,000, 6ms
    • 7 chiffres significatifs ou plus : 400,000, 12ms
  • Le choix final a été 7 chiffres significatifs, avec un dernier chiffre forcé à 0 ou 5, et 40,000 copies pour renforcer la stabilité
  • Le nombre ainsi arrondi devient une nouvelle empreinte audio qui ne change plus, même lorsque la protection avancée contre l’empreinte de Safari 17 est activée
  • Cette nouvelle empreinte est jugée aussi unique que l’ancienne

Performances et contraintes d’exécution

  • Sur une page vide et un navigateur déjà chaud, le nouvel algorithme est généralement plus lent que l’ancien
    • MacBook Air 2020 Safari 17.3 : ancien 2ms, nouvelle méthode 4ms
    • MacBook Air 2020 Chrome 120 : ancien 5ms, nouvelle méthode 8ms
    • iPhone 13 mini Safari 17.3 : ancien 8ms, nouvelle méthode 12ms
    • Galaxy J7 Prime Chrome 120 : ancien 33ms, nouvelle méthode 45ms
    • BrowserStack Windows 11 Firefox 121 : ancien 10ms, nouvelle méthode 18ms
  • Les performances du nouvel algorithme se dégradent donc d’environ 1,5 à 2 fois, mais le temps de calcul reste court même sur du matériel modeste
  • Comme le navigateur délègue une partie du travail au thread OfflineAudioRender, la page reste réactive pendant la majeure partie du calcul de l’empreinte audio
  • La Web Audio API n’étant pas disponible dans les web workers, l’empreinte audio ne peut pas être calculée dans un worker
  • Pour améliorer les performances, il est possible de détecter Safari 17 ou plus via la chaîne user-agent, d’utiliser le nouvel algorithme uniquement dans ce cas et de conserver l’ancien sur les autres navigateurs

Différences avec Tor et Brave

  • Tor désactive complètement la Web Audio API, ce qui rend l’empreinte audio impossible
  • Brave ajoute lui aussi du bruit au signal audio, comme Safari 17, mais selon une méthode différente
  • Safari multiplie chaque échantillon audio par une valeur aléatoire distincte
  • Brave génère une seule valeur aléatoire, appelée fudge factor, puis l’applique à tous les échantillons audio
    • cette valeur reste constante dans la page
    • elle ne change qu’avec une nouvelle session normale ou privée
  • Dans Brave, même en créant un grand nombre de copies d’échantillons audio, toutes reçoivent le même bruit ; la méthode mathématique de suppression du bruit conçue pour Safari ne fonctionne donc pas
  • En revanche, l’ancienne méthode de suppression du bruit de Brave continue de fonctionner, et la nouvelle génération de signal qui accentue les écarts entre navigateurs peut élargir la marge d’erreur tolérable

Intégration dans FingerprintJS

  • Le nouvel algorithme d’empreinte audio a remplacé l’ancienne méthode dans FingerprintJS et a été publié pour la première fois avec la version 4.2.0
  • Le code complet de l’implémentation est disponible dans le dépôt GitHub de FingerprintJS
  • L’empreinte audio est l’un des nombreux signaux utilisés par la bibliothèque open source pour construire une empreinte de navigateur
  • FingerprintJS n’inclut pas automatiquement tous les signaux disponibles dans le navigateur ; chaque signal est évalué séparément selon sa stabilité et son unicité afin de mesurer son impact sur la précision globale de l’empreinte
  • L’empreinte audio contribue peu à l’unicité, mais sa forte stabilité en fait un signal qui améliore légèrement la précision globale de l’empreinte

1 commentaires

 
GN⁺ 2024-03-11
Commentaires de Hacker News
  • Une autre technique intéressante pour identifier les utilisateurs en ligne est le fingerprinting GPU, présentée en 2022 sous le nom de code "DrawnApart"
    Le principe consiste à compter le nombre et la vitesse des unités d’exécution du GPU via WebGL, puis à mesurer le temps d’achèvement du rendu des sommets, le traitement des fonctions de stall, etc.

    1. https://www.bleepingcomputer.com/news/security/researchers-u...
    • Les navigateurs devraient utiliser par défaut un rendu logiciel, et lorsqu’ils ouvrent le chemin de rendu GPU matériel, les sites devraient devoir demander l’autorisation de l’utilisateur, comme pour le micro ou la caméra
  • Vu l’intérêt actuel, en particulier pour les attaques par canal auxiliaire, j’ai l’impression qu’ajouter un bruit uniforme aux valeurs qui fuient ne peut quasiment jamais fonctionner
    Il suffit de collecter davantage d’échantillons pour éliminer le bruit. Je ne comprends pas pourquoi Safari a ajouté ça. Ça peut rendre le fingerprinting plus pénible, mais comme le montre cet article, ça semble au final généralement contournable d’une manière ou d’une autre

    • Une bonne partie des fonctions de confidentialité récentes d’Apple ressemble davantage à du marketing
      On a l’impression d’un théâtre de la confidentialité où il est devenu plus important de pouvoir raconter une histoire crédible au grand public que d’être techniquement efficace
  • Quelqu’un peut-il expliquer pourquoi les résultats diffèrent au départ ? Par exemple, je me demande pourquoi le fingerprinting audio est possible

    • Le point clé semble être que la Web Audio API contient des algorithmes qui effectuent beaucoup d’opérations mathématiques, que leur implémentation varie légèrement selon les navigateurs, et que les résultats précis dépendent aussi du système d’exploitation et du CPU
      Si on génère un petit signal avec la Web Audio API, tous les navigateurs produisent presque le même résultat, mais on peut exploiter les très faibles différences pour les distinguer
    • Comme pour des techniques similaires utilisées avec WebGL, j’imagine qu’une grande partie de l’entropie vient du pilote de la carte graphique du PC et du matériel lui-même
      Il est regrettable que les développeurs de navigateurs doivent ajouter du bruit au traitement des buffers audio pour bloquer cela
    • C’était aussi ma première pensée, et c’est détaillé ici : https://fingerprint.com/blog/audio-fingerprinting/#why-the-a...
      En résumé, même au sein d’une même base de code, différents chemins de code — par exemple des variantes SIMD — peuvent produire des résultats en virgule flottante subtilement différents. Cela semble lié au fait que les opérations en virgule flottante sont plus sensibles qu’on ne le pense à l’ordre des calculs, entre autres
    • Cela vient probablement des détails d’implémentation et des optimisations du compilateur. Par exemple, l’addition en virgule flottante n’est pas commutative
      Même si on implémente correctement le même algorithme et la même formule, on peut obtenir des résultats légèrement différents
  • Corrigez-moi si je me trompe, mais il me semble que la raison du succès du contournement du fingerprinting ici tient au choix, dans la spécification de la Web Audio API, de laisser ouverte la manière de traiter l’anti-aliasing d’OscillatorNode
    "Il existe plusieurs approches pratiques qu’une implémentation peut adopter pour éviter cet aliasing. Quelle que soit l’approche, le signal audio numérique idéal en temps discret est bien défini mathématiquement. Les compromis d’implémentation se situent entre le coût en CPU et le degré de fidélité à cet idéal. On s’attend à ce que l’implémentation fasse preuve d’un certain soin pour atteindre cet idéal, mais il est raisonnable, sur du matériel peu puissant, d’envisager une approche de moindre qualité et de moindre coût."
    À mes yeux, cela signifie que la sortie d’OscillatorNode exploitée ici n’est presque certainement pas déterministe entre navigateurs, ni même sur un même navigateur avec du matériel différent. Ce caractère non déterministe repose sur la méthode d’anti-aliasing choisie par le navigateur, ou sur les différents chemins choisis dans un même navigateur selon le matériel. Cela inclut aussi les modifications ou corrections d’un même algorithme d’anti-aliasing
    Je ne comprends pas vraiment pourquoi l’anti-aliasing a été laissé à la discrétion des navigateurs. Une application ou une bibliothèque audio de haute qualité voudra contrôler entièrement la manière d’éviter l’aliasing du signal qu’elle génère, et n’utilisera probablement pas l’oscillateur par défaut. À l’inverse, une application web prête à accepter un algorithme d’anti-aliasing arbitraire et les différences entre navigateurs qui en découlent ne se souciera sans doute pas beaucoup de savoir si l’algorithme est une instruction SIMD codée en dur ou un framework d’assistance Web Audio en JavaScript de 20 Mo
    1: https://webaudio.github.io/web-audio-api/#OscillatorNode
    Je me demande s’il ne serait pas possible d’appliquer ici la même solution que celle utilisée par Hixie lors de la normalisation du parseur HTML5 : faire définir par un expert du domaine un algorithme d’anti-aliasing exact et déterministe qui fonctionne suffisamment bien, puis faire en sorte que tous les navigateurs l’utilisent. La perte de performances mesurable ne se verrait probablement que dans des cas comme les tutoriels de la Web Audio API qui génèrent des signaux avec l’oscillateur anti-aliasé par défaut

    • Un anti-aliasing de haute qualité coûte cher
      C’est pourquoi on veut laisser à l’implémentation la possibilité de décider combien de ressources de calcul, de batterie, etc., elle peut y consacrer
  • C’était une erreur de mettre dans le navigateur une API audio à graphe de nœuds. Il n’aurait fallu qu’AudioWorklet

  • Répugnant

    • C’est exactement ce que je pense aussi. C’est intéressant, mais répugnant
      Je ne comprends même pas pourquoi l’API audio est utilisable sans autorisation du site. Ça semble pouvoir être corrigé facilement avec une simple boîte de dialogue du genre « ce site veut utiliser le périphérique audio »
    • Ça amène à se demander si on peut vraiment continuer à utiliser la pile réseau actuelle pendant les 100 prochaines années
      L’internet sous sa forme actuelle a beaucoup abîmé le rêve de l’informatique personnelle. Les entreprises et les États sont bien trop asymétriquement puissants par rapport aux individus. Ma technologie devrait-elle pouvoir envoyer des données à un serveur sans approbation explicite ?
    • Oui. J’ai du mal à croire que ces gens en soient fiers
      Cela dit, après avoir vidé le cache du navigateur et activé un VPN, il m’a bien identifié à tort comme un nouveau visiteur. Malgré ça, le business model reste ignoble
    • Je trouvais qu’il y avait une certaine ironie au fait que ce soit fingerprint.com. C’est un peu comme si un site popularisait une faille permettant d’échapper à la charge fiscale, que tout le monde trouve le monde répugnant, puis qu’on finisse par refermer la faille
      Même avec une interprétation optimiste, il y a une grande valeur à publier ce type de recherche et à le rendre visible. Plutôt que de craindre qu’un article disant qu’un sac à dos vert d’une certaine marque facilite le vol pousse tout le monde à voler davantage, je pencherais plutôt pour l’idée que les magasins repéreront mieux cette méthode
  • Au lieu d’ajouter une valeur aléatoire à chaque échantillon, Safari pourrait aussi ajouter un bruit déterministe basé sur une clé qui change toutes les heures
    En le construisant comme une fonction de l’échantillon audio et de la clé, le bruit resterait le même au sein d’une session donnée, mais deviendrait inutile pour le pistage une heure plus tard

    • Si on fait ensuite la moyenne de 10 échantillons de ce genre, on finit par se rapprocher de la vraie valeur du périphérique. Plus on a d’échantillons, plus on s’en rapprochera
      Pour corriger ça, il faut éliminer la fuite d’information elle-même ; la masquer sous une couche d’écart aléatoire ne suffit pas
    • Ça n’aiderait pas si le bruit ajouté était déterministe en fonction de l’origine (origin) ? Dans ce cas, on ne pourrait pas l’éliminer en faisant une moyenne à partir d’un échantillonnage excessif
      Par exemple avec quelque chose comme RNG_SEED = HMAC_SHA256(PERSISTENT_SECRET,Location.origin)
  • Je suis maintenant vraiment prêt à devenir « cette personne » qui navigue sur le Web en désactivant JavaScript

    • Le problème, c’est que le simple fait de devenir « cette personne » risque déjà de livrer plus de 10 bits d’identification
      Il suffit ensuite de grappiller quelques bits ailleurs pour arriver à une identification unique. Cela dit, pour moi, on pourrait quand même envoyer ces gens avec le reste de l’adtech à bord du Golgafrinchan Ark B
    • Bon courage. C’est étonnant de voir à quel point le bon vieux HTML correct est rare sur le Web aujourd’hui
      Un site que j’ai visité récemment utilisait bien du balisage, mais au lieu de le compiler en HTML et de le servir statiquement, il le rendait avec du JavaScript côté client. WTF
    • Fais-le avec nous, ça se fait vraiment. Il existe une excellente extension Firefox appelée uMatrix qui permet de désactiver facilement JavaScript non seulement site par site, mais aussi sous-domaine par sous-domaine, et de le réactiver facilement sur les sites qui cassent sans JavaScript
    • Bon courage. J’ai abandonné ce combat récemment. Il fallait réactiver JavaScript sur presque tous les sites que je visitais pour voir le contenu
      Pas seulement pour les vérifications anti-DDoS comme celles de Cloudflare, mais désormais même pour des éléments qui devraient se trouver dans le HTML de la page et qui sont chargés en JavaScript
    • C’est précisément pour ça que Tor Browser impose de désactiver JavaScript
      À mesure qu’internet devient de plus en plus hostile, ce choix paraît de plus en plus juste
  • J’ai du mal à comprendre comment cette méthode peut produire plus de quelques milliers de combinaisons uniques
    Type de navigateur × version du navigateur × version du système d’exploitation × version de l’accélérateur × … quoi d’autre ? Il ne semble pas y avoir assez de variations pour que ce soit réellement unique à distance

    • La combinatoire est une maîtresse impitoyable
  • Cette technique prend-elle une empreinte à partir des différences de matériel, de pilotes et de système d’exploitation dans le traitement audio, ou regarde-t-elle seulement le logiciel du navigateur ?
    J’imagine qu’il existait ou qu’il existe encore une technique similaire qui expose les différences du matériel graphique sous-jacent

    • C’est similaire. Les algorithmes audio appellent souvent des fonctions du système d’exploitation et tirent parti des optimisations CPU
      L’un des exemples donnés dans l’article est la transformée de Fourier rapide (FFT). Tous les systèmes d’exploitation ont une version de cette fonction, mais elle tend à être optimisée avec le temps et fonctionne souvent différemment selon le CPU en fonction des instructions SIMD disponibles