Retour au Centre de connaissances
Empreinte

performance.now : résolution et fingerprinting

La résolution de performance.now() et sa gigue révèlent le lissage du minuteur, la dérive d’horloge et la charge. Mesurez-les avant de comparer deux builds.

BotBrowser Team

Documentation

Vous préférez la doc produit maintenue ?

Cet article a une page équivalente dans le centre de documentation. Utilisez les docs pour le flux canonique, les flags à jour et la référence durable.

performance.now() est la surface temporelle qu'une revue de confidentialité examine en premier : aucune demande d'autorisation ne la bloque, et sa résolution comme ses petites irrégularités décrivent la machine en dessous. BotBrowser peut rendre certaines valeurs reproductibles pour des tests autorisés, mais il ne remplace pas le matériel de l'hôte et ne promet pas l'acceptation par tous les détecteurs.

TL;DR

  • La résolution et la gigue de performance.now() sont le signal principal ici ; hardwareConcurrency et deviceMemory sont les deux valeurs lues à côté.
  • Un VPN, une fenêtre privée ou la suppression des cookies ne change pas les surfaces matérielles locales.
  • Les options de temps BotBrowser servent à une validation reproductible, pas à garantir l’anonymat ou l’acceptation par un détecteur.

Contents

Ce que performance.now() révèle de l’horloge

Les API de temps ont été conçues pour aider les développeurs à mesurer leur propre code, mais la même horloge permet à un site web d'observer quelque chose de la machine qui l'exécute. performance.now() est la surface qui porte le plus d'information par octet, parce que deux propriétés de la lecture se décident hors de la page : la finesse de l'horloge et l'amplitude des oscillations entre lectures successives.

La fonction renvoie un horodatage haute résolution mesuré depuis le début de l'origine des temps de la page. Les navigateurs dégradent volontairement cette horloge, et la référence MDN précise que la résolution plus fine n'est offerte qu'aux pages isolées en origine croisée, tandis que certains modes du navigateur axés sur la confidentialité l'arrondissent davantage. Le lissage change la résolution, pas la forme. Un script qui répète le même travail mesure toujours la durée de ce travail, et cette durée dépend de la vitesse du processeur, du comportement du cache, de l'ordonnancement et de la charge de la machine à ce moment précis.

Cette dégradation a une histoire. On a montré que les horloges haute résolution pouvaient servir à des attaques par canal auxiliaire de type Spectre, de sorte que les éditeurs de navigateurs ont réduit la précision des minuteurs, ajouté de la gigue et réservé la meilleure précision à l'isolation en origine croisée. Cette mesure a été conçue pour protéger le contenu de la mémoire, pas pour retirer la forme du matériel du tableau. Un minuteur grossier lu de nombreuses fois continue d'apporter des informations sur la durée d'une tâche sur une machine donnée, et l'écart entre ces lectures est aussi parlant que les lectures elles-mêmes.

Deux autres valeurs accompagnent souvent l'horloge, et cet article les traite comme un contexte plutôt que comme son sujet. hardwareConcurrency indique le nombre de processeurs logiques disponibles pour le navigateur, et les appareils réels se regroupent autour de valeurs comme 4, 8, 12 et 16. deviceMemory renvoie une classe de RAM approximative en gigaoctets, arrondie à une puissance de deux et plafonnée, et les navigateurs basés sur Chromium ne l'exposent que dans des contextes sécurisés. Le guide de dimensionnement des workers explique comment calibrer un pool à partir de ce nombre de cœurs ; ici, l'essentiel est qu'une lecture de temps est plus distinctive lorsqu'on la compare à elles.

Schéma : l'horloge de performance.now, le nombre de cœurs logiques et la classe de mémoire forment un même profil de temps façonné par le matériel, comparé au profil chargé

Aucune de ces valeurs ne demande d'autorisation, aucune n'affiche d'indicateur visible et aucune n'est effacée quand vous supprimez les cookies. C'est pourquoi elles apparaissent dans la recherche sur les empreintes, même si chaque nombre semble anodin pris isolément. Les sections suivantes expliquent comment les lectures se combinent, quelles mesures de confidentialité courantes les laissent intactes et comment vous pouvez configurer et vérifier un temps rapporté cohérent avec BotBrowser.

Pourquoi la combinaison est plus distinctive

Pris seul, chacun de ces signaux apporte peu d'information. De nombreux appareils partagent le même nombre de cœurs et la classe de mémoire n'a que quelques valeurs possibles. La combinaison est différente, car un site peut lire les trois d'un coup et y ajouter un court échantillon de temps. Un appareil qui renvoie une dispersion particulière de deltas de performance.now(), huit cœurs et une classe de mémoire de 8 Go tombe dans un groupe bien plus petit que celui décrit par l'un quelconque de ces éléments.

La combinaison est aussi comparée au reste du navigateur. Les relecteurs voient régulièrement les valeurs de temps et de matériel lues à côté du moteur de rendu graphique, de la taille d'écran, de la chaîne de plateforme et de la liste de polices, et une page peut vérifier si elles décrivent la même machine. Un profil qui prétend être un portable modeste mais renvoie les temps d'une station de travail rapide, ou l'inverse, est plus distinctif qu'un profil simplement ordinaire.

Imaginez la revue d'un profil de test qui décrit un portable de milieu de gamme avec huit cœurs logiques et une classe de mémoire de 8 Go. Sur une page que vous contrôlez, le nombre de cœurs et la classe de mémoire se lisent comme prévu. Un échantillon de temps montre ensuite que la boucle se termine bien plus vite que ne le ferait un portable de cette classe, parce que l'hôte réel est un serveur haut de gamme. Chaque valeur matérielle concorde avec le profil, mais le temps ne concorde pas avec elles. En pratique, la plage d'échelle documentée, de 0.80 à 0.99, est étroite : elle peut atténuer un écart modeste, mais pas transformer une classe de matériel en une autre, et seul un relecteur qui lit les surfaces ensemble remarquera l'écart.

La stabilité compte autant que les valeurs elles-mêmes. Un nombre de cœurs qui change d'un chargement de page à l'autre, ou un temps qui se comporte d'une façon dans un onglet et d'une autre dans le suivant, est plus distinctif qu'une valeur stable mais banale. C'est la raison principale pour laquelle une graine reproductible est utile en revue : elle supprime une source de variation, et toute différence restante entre deux exécutions renvoie donc à autre chose.

C'est pourquoi ce sujet relève de la cohérence et non de la dissimulation. L'objectif d'une revue de confidentialité rigoureuse n'est pas de réduire chaque nombre au minimum. Il s'agit de s'assurer que la forme matérielle rapportée par une surface concorde avec celle rapportée par les autres, et que cet accord tient à chaque chargement de page, dans chaque worker et dans la durée.

Trois questions aident à structurer une revue :

  • hardwareConcurrency et deviceMemory décrivent-ils la même classe de machine que le profil chargé ?
  • Les échantillons de temps répétés sur une page ressemblent-ils à cette même classe de machine, et restent-ils proches d'une exécution à l'autre ?
  • Les entrées de Navigation Timing et de Resource Timing sont-elles cohérentes avec le profil au lieu de refléter la connexion réelle de l'hôte ?

Ce que laissent en place les VPN, les fenêtres privées, les extensions et le bruit

Comparez performance.now(), navigator.hardwareConcurrency et navigator.deviceMemory dans le même profil; les outils de confidentialité réseau ne réécrivent pas ces valeurs locales.

Un VPN change le chemin réseau et l'adresse IP que voit un serveur. Il ne change pas la vitesse à laquelle votre processeur exécute une boucle, le nombre de cœurs logiques que le navigateur annonce ni la classe de mémoire qu'il expose. Les trois valeurs sont lues en local : deux machines différentes derrière le même point de sortie de VPN annoncent donc toujours des formes matérielles différentes.

Les fenêtres de navigation privée suppriment cookies, historique et données de site à leur fermeture. Elles ne changent ni le nombre de cœurs, ni la classe de mémoire, ni la vitesse du matériel sous-jacent, si bien que les valeurs de temps et de matériel d'une fenêtre privée sont celles d'une fenêtre normale sur la même machine.

Réinstaller le navigateur, passer à un autre navigateur sur le même ordinateur ou effacer toutes les données de site laisse en place le même processeur, le même nombre de cœurs et la même mémoire. Des navigateurs différents peuvent annoncer des valeurs différentes selon leurs propres règles d'arrondi et de plafonnement, mais un navigateur sur une machine reste stable, et c'est précisément pourquoi ces valeurs fonctionnent comme un signal durable.

Les extensions qui remplacent des propriétés matérielles injectent généralement un script qui redéfinit une propriété dans la page. Cela peut laisser des traces visibles, comme des descripteurs de propriété différents de ceux du navigateur, ou un cadre neuf qui lit la valeur réelle avant l'exécution de l'extension. Cela peut aussi créer des contradictions : une page qui annonce quatre cœurs alors qu'un groupe de workers exécute visiblement plus de tâches en parallèle se remarque plus facilement qu'une valeur non modifiée.

Le bruit aléatoire ajouté aux valeurs de temps pose un problème voisin. Une suite d'horodatages avec une gigue artificielle ne ressemble pas à la variation d'un matériel réel, elle peut perturber la surveillance légitime des performances sur les pages que vous visitez, et un bruit qui change à chaque appel est lui-même un motif visible. Des valeurs rapportées stables et plausibles sont généralement plus faciles à défendre que des valeurs aléatoires.

Certains navigateurs intègrent leurs propres protections, comme une précision de minuteur réduite ou un nombre de cœurs plafonné. Elles réduisent l'information qu'une page peut lire, mais elles s'appliquent à tous ceux qui utilisent le même mode : les valeurs rapportées deviennent communes plutôt qu'uniques. Elles ne font pas non plus correspondre les valeurs à une classe de matériel précise, de sorte que la cohérence avec un profil choisi doit toujours être vérifiée séparément.

Rien de tout cela ne rend ces outils inutiles. Un VPN protège la couche réseau, les fenêtres privées protègent l'historique local et les extensions peuvent bloquer de nombreux traceurs avant leur chargement. Ils couvrent des surfaces différentes. La forme du temps et du matériel est une surface qu'ils n'ont jamais été conçus pour couvrir : une revue doit donc la traiter séparément et la vérifier directement.

Configurer le temps rapporté avec un profil BotBrowser

Partez d'un profil, car c'est lui qui définit les valeurs matérielles avec lesquelles les options de temps doivent rester cohérentes. Un lancement avec le seul profil vous donne une base de comparaison avant d'ajouter la moindre option de temps. Ajoutez ensuite les options une par une et notez ce qui change. Enregistrez la sortie de la console de chaque étape dans un fichier texte brut à côté de la commande de lancement.

chromium-browser \
  --bot-profile="path/to/profile.enc" \
  --bot-time-scale=0.92 \
  --bot-time-seed=42

--bot-time-scale compresse les intervalles de temps haute résolution rapportés. La plage documentée va de 0.80 à 0.99, et une valeur plus proche de 0.80 compresse davantage les intervalles qu'une valeur proche de 0.99. La documentation décrit l'effet comme l'émulation d'une charge système plus faible et la réduction des signaux de biais temporel. C'est une option ENT Tier2.

--bot-time-seed accepte un entier de 1 à 4294967295, et 0 la désactive. Chaque graine produit un profil de temps stable qui répartit une diversité déterministe sur les opérations du navigateur et les entrées de navigation timing, de sorte que la même graine avec le même profil donne le même comportement à l'exécution suivante. C'est aussi une option ENT Tier2.

Utilisez une graine différente par instance quand vous voulez que les instances diffèrent, et gardez une graine fixe quand vous voulez qu'un test soit répétable. La documentation sur les performances cite des temps identiques d'une instance à l'autre comme le symptôme de la réutilisation d'une même graine. L'échelle et la graine traitent des aspects différents du temps, et la documentation indique qu'elles peuvent être utilisées ensemble.

--bot-performance-timing est une option distincte pour les entrées de temps visibles par le navigateur, comme les étapes de connexion dans Navigation Timing et Resource Timing. Elle accepte basic et advanced, exige ENT Tier3 et ne fonctionne que si le paquet de profil actif active Performance Timing Protection. Elle doit être définie avant le démarrage de la première page ou du premier worker et est résolue par contexte de navigation. Omettez-la, ou passez false, pour laisser la politique désactivée.

Travaillez dans un ordre fixe. Lancez la base avec le seul profil et conservez la sortie de vérification. Ajoutez l'échelle de temps et comparez. Ajoutez la graine et comparez encore. Ajoutez --bot-performance-timing en dernier, et seulement si votre niveau et votre profil le prennent en charge, car elle touche un ensemble de surfaces différent des deux autres. Tout changer en même temps rend impossible de savoir quelle option a produit quelle différence. Consultez la référence des options de la CLI pour votre niveau avant de planifier un test, afin qu'un résultat qui semble faux ne soit pas simplement une option que votre niveau ne couvre pas.

Vérifier que le temps reste cohérent

N'exécutez la vérification que sur des pages et des sessions de test que vous êtes autorisé à utiliser. Ouvrez une page vierge que vous contrôlez, lancez avec le profil et les options ci-dessus, puis comparez ce que vous lisez à ce que décrit le profil. Notez le profil avec lequel vous avez lancé avant de lire la moindre valeur, pour que la comparaison ne se fasse pas de mémoire. Le fragment ci-dessous peut être collé dans la console de développement de cette page.

const { hardwareConcurrency, deviceMemory } = navigator;
const samples = [];
for (let run = 0; run < 5; run += 1) {
  const start = performance.now();
  for (let i = 0; i < 100000; i += 1) Math.sqrt(i);
  samples.push(performance.now() - start);
}
console.log({ hardwareConcurrency, deviceMemory, samples });

Le fragment lit les deux valeurs matérielles et recueille cinq courts échantillons de temps. Considérez la sortie comme un contrôle de cohérence plutôt que comme un banc d'essai : les valeurs absolues dépendent de l'hôte, et ce que vous cherchez est l'accord entre les valeurs rapportées et le profil.

Ce qu'il faut vérifier :

  1. hardwareConcurrency correspond au nombre de cœurs que décrit le profil.
  2. deviceMemory correspond à la classe de mémoire que décrit le profil.
  3. Les cinq échantillons sont proches les uns des autres, et un second lancement avec le même profil, la même échelle et la même graine produit un motif cohérent.
  4. Ne changer que la graine modifie le motif, ce qui confirme que la graine est appliquée.
  5. Lire les mêmes valeurs dans un worker dédié et dans une iframe donne les mêmes valeurs matérielles que la page principale.

Les échantillons de temps ne seront jamais identiques, et ils ne doivent pas l'être. Un matériel réel varie légèrement d'une exécution à l'autre en raison de l'ordonnancement et de l'état du cache. Un jeu d'échantillons parfaitement plat, ou qui oscille sans contrôle, mérite plus de méfiance qu'un jeu à faible variation naturelle.

Les valeurs matérielles et de temps devraient se lire de la même façon partout où un script s'exécute. Un site peut créer des workers dédiés et des cadres aussi facilement qu'il lit la page principale : un écart entre eux est donc facile à trouver. Testez aussi ces contextes et traitez toute différence comme un constat à consigner plutôt que comme une anomalie à justifier.

Si un résultat ne correspond pas, changez un réglage à la fois et recommencez, ce qui est la démarche recommandée par la documentation sur les performances pour le dépannage. Les causes courantes sont une graine absente ou erronée, un profil qui n'inclut pas la fonction ou un niveau ENT qui ne couvre pas l'option.

Les pages publiques de test d'empreinte peuvent donner un second avis, mais elles ne publient pas de critères de réussite garantis, et un résultat propre sur une page n'est pas une promesse pour un autre site. Traitez chaque page comme un seul point de données et comparez plusieurs exécutions avant de conclure. Conservez la commande de lancement exacte avec les résultats afin qu'un autre relecteur puisse refaire l'exécution plus tard.

Ce que BotBrowser apporte et où il s'arrête

BotBrowser documente --bot-time-scale et --bot-time-seed (ENT Tier2) pour produire, dans le contenu de la page, un profil de temps stable et reproductible par graine à côté des valeurs matérielles définies par le profil. BotBrowser ne peut pas changer la vitesse à laquelle l'hôte exécute réellement JavaScript, ne remplace pas le matériel physique et ne garantit pas que chaque surface de temps ou chaque détecteur tiers accepte le résultat; les options dépendent du niveau ENT et de la prise en charge par le profil, --bot-performance-timing exigeant en plus ENT Tier3 et un profil qui l'active.

En pratique, le résultat utile est une base reproductible. Vous pouvez consigner le profil, l'échelle et la graine, refaire les mêmes vérifications un autre jour et voir si quelque chose a dérivé dans la forme du matériel ou du temps. C'est une affirmation plus étroite que cacher un appareil, et c'est celle que les options sont documentées pour soutenir.

Ces valeurs décrivent un appareil et non une personne. La forme du temps et du matériel est une entrée parmi beaucoup d'autres, et aucune valeur isolée ne décide de la façon dont un site traite un visiteur. Cette page n'affirme rien sur la précision avec laquelle un traceur identifie un appareil ; le but est de vous aider à vérifier que ce que rapporte votre navigateur est cohérent en interne et honnêtement documenté.

Un dossier de revue est plus utile lorsqu'il indique :

  • Le fichier de profil et la version de BotBrowser utilisée.
  • Les options exactes, y compris l'échelle et la graine.
  • Le niveau ENT disponible pour l'exécution.
  • Les valeurs matérielles et les échantillons de temps lus.
  • La date et la page utilisée pour la vérification.

Ces lectures couvrent les surfaces voisines. Le guide général sur les empreintes du navigateur explique comment les signaux se combinent, hardwareConcurrency et la planification des workers examine plus en détail le nombre de cœurs et le contrôle de la fréquence d'images traite de l'option de temps d'affichage.

Sources publiques

Conclusion pratique

Utilisez les valeurs de temps et de matériel comme des indices de cohérence, pas comme la promesse qu'un navigateur sera indiscernable d'une autre machine. Commencez par une base avec le profil seul, changez une option prise en charge à la fois, notez la commande exacte et le niveau ENT, puis répétez les contrôles autorisés dans la page, le worker et l’iframe. En cas d’écart, consignez-le et examinez le profil ou l’hôte au lieu d’ajouter un bruit inexpliqué.

#performances#Timing#fingerprinting#confidentialité#Cpu#Hardware#Time-Seed

Cet article fait partie du guide : Qu'est-ce qu'une empreinte de navigateur ?

Faites passer BotBrowser de la recherche à la production

Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.