Contrôle du nombre de cœurs CPU avec BotBrowser
Comment navigator.hardwareConcurrency expose l'identité CPU pour le fingerprinting, et comment BotBrowser contrôle le nombre de cœurs rapporté dans tous les contextes.
Introduction
La propriété navigator.hardwareConcurrency renvoie le nombre de cœurs logiques CPU disponibles pour le navigateur. Elle a été conçue pour aider les applications Web à optimiser les charges de travail parallèles, permettant au code JavaScript de décider combien de Web Workers créer ou comment partitionner le traitement des données. Mais cette même propriété révèle des informations matérielles qui contribuent au fingerprinting du navigateur. Un appareil avec 6 cœurs logiques est beaucoup moins courant qu'un appareil avec 8, et un serveur avec 64 cœurs se remarque immédiatement. Parce que le nombre de cœurs est stable, facile à consulter et varie selon les configurations matérielles, il est devenu un composant standard dans les systèmes de suivi. Cet article explique comment le nombre de cœurs contribue au fingerprinting, pourquoi les substitutions simples posent problème, et comment BotBrowser fournit un rapport cohérent du nombre de cœurs via son système de profils.
Impact sur la vie privée
Le nombre de cœurs peut sembler une faible source d'information, mais sa contribution est significative en contexte. La valeur de tout attribut de fingerprint dépend de sa distribution dans la population. D'après les données du projet AmIUnique, navigator.hardwareConcurrency a environ 4,5 bits d'entropie, ce qui signifie qu'il peut distinguer environ 23 groupes différents. Bien que 23 groupes ne paraissent pas beaucoup, chaque bit d'entropie supplémentaire double approximativement la puissance d'identification lorsqu'il est combiné à d'autres signaux.
La distribution est fortement biaisée. Les valeurs 4 et 8 représentent la majorité des navigateurs de bureau. Les valeurs 2 (machines anciennes, Chromebooks bas de gamme), 6 (certaines configurations Intel), 12 (Ryzen 5), 16 (machines haut de gamme) et tout ce qui dépasse 16 sont progressivement plus rares. Une machine déclarant 24, 32 ou 64 cœurs est presque certainement un serveur ou une station de travail, extrêmement rare dans la population de navigation normale.
Les appareils mobiles ajoutent une différenciation supplémentaire. La plupart des téléphones déclarent 4 ou 8 cœurs, mais certaines familles de SoC (Snapdragon, Exynos, MediaTek, Apple Silicon) associent des nombres de cœurs spécifiques à d'autres propriétés identifiables. Un téléphone avec hardwareConcurrency = 8 combiné à un pattern de user agent spécifique réduit la liste des modèles possibles.
Le problème de confidentialité est amplifié car hardwareConcurrency est disponible dans tous les contextes d'exécution : fil principal, dedicated workers, shared workers et service workers. Il ne nécessite aucune permission et ne peut être bloqué sans casser des applications Web légitimes qui l'utilisent pour l'optimisation des performances.
Contexte technique
Comment fonctionne hardwareConcurrency
La propriété navigator.hardwareConcurrency renvoie un entier non signé représentant le nombre de processeurs logiques disponibles. « Processeurs logiques » signifie le nombre de cœurs physiques multiplié par le nombre de threads par cœur (par ex., un CPU 4 cœurs avec hyperthreading rapporte 8).
console.log(navigator.hardwareConcurrency); // ex. 8
La valeur est également accessible dans les contextes worker :
// Dans un Web Worker
console.log(self.navigator.hardwareConcurrency); // même valeur
Pourquoi la valeur varie
Plusieurs facteurs déterminent ce que renvoie hardwareConcurrency :
- Matériel physique. Le nombre de cœurs et de threads dépend du modèle du processeur. Les Intel i5 ont souvent 4-6 cœurs avec hyperthreading. Les AMD Ryzen 7 ont 8 cœurs avec SMT. Les puces Apple M-series ont des nombres de cœurs variables entre clusters d'efficacité et de performance.
- Virtualisation. Les machines virtuelles rapportent le nombre de vCPU alloués, qui peut différer de l'hôte. Une VM avec 2 vCPU rapporte
hardwareConcurrency= 2. - Ordonnancement OS. Certains systèmes ou environnements conteneurisés permettent de limiter le nombre de processeurs visibles.
- Implémentation du navigateur. La plupart des navigateurs rapportent la valeur brute fournie par l'OS. Certains ont expérimenté des limites ou des bucketings, mais Chromium rapporte généralement le compte réel.
Corrélation avec d'autres signaux
Le nombre de cœurs n'existe pas isolément. Les systèmes de tracking le croisent avec :
navigator.deviceMemory— par ex. 2 cœurs avec 8 Go est plausible ; 2 cœurs avec 0,25 Go suggère une autre classe d'appareil.navigator.platform— « Linux x86_64 » avec 4 cœurs restreint le matériel possible ; « Linux armv81 » avec 8 cœurs suggère un serveur ARM ou un téléphone.- User agent. La version navigateur et OS contraint les recensements de cœurs réalistes.
- Timing de performance. La performance parallèle réelle (mesurée via timing) peut être comparée au nombre de cœurs déclaré.
Une incohérence entre le nombre de cœurs déclaré et la performance observable est un fort signal de falsification.
Approches de protection courantes et leurs limites
Surcharger hardwareConcurrency manuellement via extension ou injection JS est l'approche la plus courante. Cela change la valeur renvoyée mais pose des problèmes :
- Incohérence de performance. Si vous signalez 4 cœurs mais que la machine réelle en a 16, les charges parallèles s'exécuteront plus vite que sur une vraie machine 4 cœurs.
- Détection prototype. Les surcharges JS peuvent être détectées en inspectant le descriptor de propriété, la chaîne prototype ou le temps d'exécution du getter.
- Gaps dans les workers. Certaines extensions n'appliquent la modification qu'au thread principal et ne patchent pas les workers.
Aléatoriser la valeur produit des configurations peu plausibles (p.ex. 7 ou 13).
Utiliser une valeur commune fixe (toujours 8) est mieux que l'aléatoire, mais peut entrer en contradiction avec d'autres signaux (user agent indiquant un téléphone 4 cœurs).
La règle fondamentale est que la valeur rapportée doit être cohérente avec les autres propriétés de l'appareil et ne doit pas contredire des caractéristiques de performance observables.
Approche au niveau moteur de BotBrowser
BotBrowser contrôle navigator.hardwareConcurrency au niveau moteur Chromium via son système de profils. Cette méthode présente plusieurs avantages par rapport aux modifications JS.
Valeurs pilotées par profil
Chaque profil de fingerprint BotBrowser spécifie une valeur hardwareConcurrency correspondant à la configuration CPU réelle du dispositif profilé. Un profil desktop Windows 10 avec Intel i7 renverra 8 ou 16 cœurs. Un profil Android avec Snapdragon 888 renverra 8 cœurs. Les valeurs proviennent de configurations réelles, pas d'entiers arbitraires.
Cohérence dans tous les contextes
Étant donné que le contrôle se fait au niveau du moteur, tous les contextes renvoient la même valeur :
- Thread principal
navigator.hardwareConcurrency - Dedicated Worker
self.navigator.hardwareConcurrency - Shared Worker
self.navigator.hardwareConcurrency - Service Worker
self.navigator.hardwareConcurrency
Il n'existe pas de gap où un contexte montre la valeur réelle et un autre la valeur du profil.
Cohérence inter-signaux
La valeur hardwareConcurrency du profil fait partie d'une identité appareil complète. Elle s'aligne avec :
- La chaîne user agent et la plateforme
- Le deviceMemory
- La résolution d'écran et d'autres signaux matériels
- La marque et la version du navigateur
Ceci empêche les vérifications croisées de révéler des incohérences.
Pas d'artefacts JavaScript
Parce que la valeur est définie au niveau du moteur, il n'y a pas de descriptors modifiés ni de getters non natifs ni de différences temporisées. La propriété se comporte comme sur le matériel profilé.
Configuration et utilisation
Chargement de profil basique
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Le profil détermine automatiquement le nombre de cœurs rapporté.
Vérifier la valeur
// Console navigateur ou script d'automatisation
console.log(navigator.hardwareConcurrency);
// Retourne le nombre du profil, pas du matériel réel
Intégration Playwright
const { chromium } = require('playwright');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log(`Reported cores: ${cores}`);
// Vérifier la cohérence dans les workers
const workerCores = await page.evaluate(() => {
return new Promise(resolve => {
const blob = new Blob([
'postMessage(self.navigator.hardwareConcurrency)'
], { type: 'application/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
worker.onmessage = e => resolve(e.data);
});
});
console.log(`Worker cores: ${workerCores}`);
Intégration Puppeteer
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
defaultViewport: null,
args: [
'--bot-profile=/path/to/profile.enc'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log(`Reported cores: ${cores}`);
Vérification
Contrôle de la valeur. Interrogez navigator.hardwareConcurrency et confirmez qu'il correspond à la valeur attendue du profil chargé.
Cohérence dans les workers. Créez un Web Worker et interrogez self.navigator.hardwareConcurrency ; la valeur doit correspondre à celle du thread principal.
Cohérence inter-propriétés. Vérifiez que le nombre de cœurs est plausible par rapport à la plateforme, au user agent et au deviceMemory du profil.
Stabilité entre sessions. La valeur doit être identique sur plusieurs sessions utilisant le même profil.
Bonnes pratiques
- Utilisez un profil complet. N'essayez pas de surcharger
hardwareConcurrencyisolément. - Choisissez des profils réalistes. Les valeurs courantes (4, 8) s'intègrent mieux que des valeurs inhabituelles (6, 12, 24).
- Testez en contexte worker. Assurez-vous que les workers renvoient la même valeur que le thread principal.
- Évitez les surcharges manuelles. Les profils BotBrowser sont conçus pour la cohérence interne ; modifier manuellement le nombre de cœurs sans ajuster les autres propriétés crée des incohérences détectables.
FAQ
Q : Quels sont les valeurs les plus courantes de hardwareConcurrency ? R : Sur desktop, 4 et 8 sont de loin les plus courantes, représentant plus de 70% des navigateurs. Sur mobile, 4 et 8 dominent également. Les valeurs 2, 6, 10, 12, 16 et supérieures deviennent progressivement rares.
Q : Un site peut-il mesurer mon nombre réel de cœurs indépendamment de hardwareConcurrency ? R : Théoriquement, un site pourrait tenter de mesurer la performance parallèle via SharedArrayBuffer et des timers haute résolution, mais les mitigations de sécurité du navigateur (réduction de la précision des timers, exigences COOP/COEP) rendent cela difficile. Le contrôle au niveau moteur de BotBrowser aide aussi à la cohérence.
Q : hardwareConcurrency change-t-il avec les mises à jour du navigateur ? R : Non. La valeur reflète la configuration matérielle et du système d'exploitation, pas la version du navigateur.
Q : navigator.hardwareConcurrency est-il disponible dans tous les navigateurs ? R : Oui. Les navigateurs majeurs (Chrome, Firefox, Safari, Edge) le supportent et il est normalisé dans la spécification HTML.
Q : Pourquoi certaines VMs rapportent-elles des comptes différents de l'hôte ? R : Les VMs montrent le nombre de vCPU attribués par l'hyperviseur ; l'hôte peut avoir plus de cœurs, mais la VM ne voit que ceux assignés.
Q : Le nombre de cœurs affecte-t-il la performance des Web Workers dans BotBrowser ? R : BotBrowser contrôle la valeur rapportée, pas l'ordonnancement réel du CPU. L'exécution s'effectue toujours sur le matériel réel ; la valeur n'affecte que ce que JavaScript voit.
Résumé
navigator.hardwareConcurrency est une propriété simple mais significative pour le fingerprinting lorsqu'elle est combinée à d'autres signaux. BotBrowser contrôle cette valeur au niveau moteur via des profils, garantissant la cohérence dans tous les contextes d'exécution JavaScript et l'alignement avec le reste des signaux d'identité.
Pour des sujets connexes, voir What is Browser Fingerprinting, Navigator Property Protection et Deterministic Browser Behavior.
title: "Controle du nombre de coeurs CPU avec BotBrowser" description: "Comment BotBrowser controle navigator.hardwareConcurrency a travers les profils d'empreinte pour un rapport de coeurs CPU coherent dans tous les contextes." date: "2025-05-14" locale: fr category: fingerprint tags: ["cpu", "cores", "hardwareConcurrency", "fingerprinting", "privacy"] published: true
Le risque pour la vie privee
navigator.hardwareConcurrency retourne le nombre de coeurs logiques du processeur disponibles pour le navigateur. Cette valeur est un signal de suivi car elle revele la classe d'appareil : serveur, ordinateur de bureau, portable ou mobile. Elle ne requiert aucune permission et est accessible depuis le thread principal, les Web Workers et les iframes.
La solution BotBrowser
BotBrowser definit le nombre de coeurs depuis le profil d'empreinte au niveau du moteur du navigateur, avant l'execution de tout JavaScript. La valeur est coherente dans tous les contextes d'execution.
Charger un profil
chrome --bot-profile="/profiles/windows-chrome-122.enc" \
--user-data-dir="$(mktemp -d)"
Si le profil a ete capture depuis un ordinateur de bureau a 8 coeurs, navigator.hardwareConcurrency retourne 8 que la machine hote ait 2 coeurs ou 96 coeurs.
Tous les contextes correspondent
Le nombre de coeurs du profil s'applique a :
navigator.hardwareConcurrencyde la page principale- Les contextes Web Worker et SharedWorker
- Les contextes Service Worker
- Les objets navigator des iframes
Automatisation sur serveur
Lors de l'execution sur un serveur cloud, le nombre de coeurs de l'hote revelerait un environnement serveur. BotBrowser presente le nombre de coeurs d'un appareil grand public du profil :
const { chromium } = require('playwright-core');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/profiles/windows-chrome-122.enc',
],
headless: true,
});
const page = await (await browser.newContext()).newPage();
const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log('Coeurs rapportes:', cores); // 8, pas 96
Verification
Verifiez la coherence du nombre de coeurs entre les contextes :
const page = await (await browser.newContext()).newPage();
const mainCores = await page.evaluate(() => navigator.hardwareConcurrency);
const workerCores = await page.evaluate(() => {
return new Promise(resolve => {
const blob = new Blob([
'self.postMessage(navigator.hardwareConcurrency)'
], { type: 'application/javascript' });
const w = new Worker(URL.createObjectURL(blob));
w.onmessage = e => resolve(e.data);
});
});
console.log('Thread principal:', mainCores);
console.log('Web Worker:', workerCores);
console.log('Correspondance:', mainCores === workerCores);
Les deux valeurs doivent correspondre au nombre de coeurs enregistre dans le profil, pas au nombre reel de la machine hote.
Pour commencer
- Telechargez BotBrowser depuis GitHub
- Choisissez un profil depuis le depot de profils
- Lancez avec
--bot-profilepour appliquer l'identite materielle complete - Verifiez avec
navigator.hardwareConcurrencydans la console du navigateur