Cohérence des signaux CSS avec BotBrowser
Comment les media queries CSS et des caractéristiques comme la profondeur de couleur et prefers-color-scheme créent des signaux d'empreinte, et comment BotBrowser garantit la cohérence.
Introduction
Le CSS est souvent négligé comme vecteur d'empreinte car il est principalement un langage de style. Pourtant, les media queries CSS exposent des informations sur l'écran de l'utilisateur, ses préférences et les capacités du navigateur. Des propriétés telles que prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution et forced-colors révèlent des détails de configuration qui contribuent à une empreinte. Ce qui rend le fingerprinting basé sur le CSS particulièrement efficace, c'est qu'il fonctionne sans JavaScript. Une feuille de style bien construite peut extraire des informations via le chargement conditionnel de ressources, rendant la technique invisible aux outils de confidentialité basés sur les scripts. Cet article explique comment les signaux CSS contribuent au fingerprinting et comment BotBrowser veille à ce que les media queries CSS, les appels matchMedia() en JavaScript et les APIs associées retournent des valeurs cohérentes et pilotées par le profil.
Impact sur la vie privée
Le fingerprinting CSS a suscité l'attention dans la recherche en confidentialité car il opère sur une couche différente du fingerprinting JavaScript. Une étude a montré que l'interrogation simultanée de 15+ caractéristiques pouvait, à elle seule, distinguer environ 30 % des utilisateurs. Combinées aux propriétés accessibles par JavaScript (qui doivent être cohérentes avec les valeurs CSS), les capacités d'identification augmentent notablement.
La spécification W3C Media Queries Level 5 reconnaît le potentiel de ces caractéristiques pour le fingerprinting. Des caractéristiques comme prefers-color-scheme, prefers-contrast, prefers-reduced-motion et prefers-reduced-data indiquent des préférences utilisateur qui varient selon la population. Chaque caractéristique a généralement une faible entropie (souvent binaire ou quelques valeurs possibles), mais la combinaison de nombreuses caractéristiques crée une empreinte significative.
Le fingerprinting CSS est particulièrement préoccupant car il peut fonctionner sans exécution de JavaScript. Un pixel de suivi chargé conditionnellement par une règle @media informe le serveur de la configuration d'affichage simplement via la requête. Ainsi, même les utilisateurs bloquant entièrement JavaScript peuvent être partiellement fingerprintés via CSS.
Contexte technique
Caractéristiques CSS pertinentes pour le fingerprinting
Les media queries CSS testent des conditions sur l'environnement de l'utilisateur. Les caractéristiques suivantes sont les plus pertinentes :
Propriétés d'affichage :
resolution/min-resolution/max-resolution— densité de pixels de l'écran (dpi ou dppx).color— nombre de bits par composante de couleur.color-index— nombre de couleurs dans la table LUT.color-gamut— gamut approximatif :srgb,p3ourec2020.monochrome— si l'appareil est monochrome et bits par pixel.
Préférences utilisateur :
prefers-color-scheme— préférencelightoudark.prefers-reduced-motion— si l'utilisateur demande de réduire le mouvement.prefers-contrast— haute ou basse contraste.prefers-reduced-transparency— réduction de la transparence.forced-colors— mode couleurs forcées (Windows High Contrast).
Viewport et affichage :
width/height— dimensions du viewport.device-width/device-height— dimensions d'écran (dépréciées mais encore supportées).aspect-ratio— ratio du viewport.orientation—portraitoulandscape.
Interaction :
hover— si le dispositif primaire peut faire hover.any-hover— si un quelconque dispositif peut faire hover.pointer— précision du pointeur :none,coarse, oufine.any-pointer— existence d'un pointeur disponible.
Comment fonctionne le fingerprinting CSS
Le fingerprinting CSS peut être réalisé de deux manières.
Basé sur JavaScript : Utiliser window.matchMedia() pour tester des media queries :
const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const highDPI = window.matchMedia('(min-resolution: 2dppx)').matches;
const p3Gamut = window.matchMedia('(color-gamut: p3)').matches;
Pur CSS (sans JavaScript) : Utiliser le chargement conditionnel de ressources :
@media (prefers-color-scheme: dark) {
.tracker { background-image: url('https://track.example.com/dark'); }
}
@media (prefers-color-scheme: light) {
.tracker { background-image: url('https://track.example.com/light'); }
}
Le serveur détermine la préférence de thème en fonction de l'URL demandée. En chaînant plusieurs conditions, une feuille CSS peut extraire des dizaines de signaux binaires.
Pourquoi les signaux CSS varient
Les valeurs des caractéristiques CSS dépendent de :
- Matériel. Les capacités de l'écran déterminent gamut, profondeur de couleur et résolution.
- Paramètres OS. Le mode sombre, le contraste élevé, la réduction de mouvement sont des préférences au niveau système.
- Configuration du navigateur. Certains navigateurs remplacent les préférences OS. Les modes privés peuvent modifier certains valeurs.
- Type d'appareil. Les appareils tactiles rapportent
pointer: coarseethover: none, les desktops rapportentpointer: fineethover: hover.
Le problème de la cohérence
La difficulté consiste à maintenir la cohérence entre de nombreux signaux simultanément. Si @media indique un thème sombre mais screen.colorDepth indique une configuration incompatible, ou si des ressources CSS montrent un état différent de celui rapporté par JS, cette incohérence devient un signal d'empreinte.
Approches courantes et limites
Extensions navigateur peuvent intercepter window.matchMedia() mais ne pas modifier les règles @media au niveau de la feuille de style. Une page peut détecter via CSS pur tandis que l'extension ne touche que l'API JS, créant une incohérence détectable.
Désactiver CSS casse l'expérience web, donc non viable.
Standardiser les préférences (toujours reporter light, no reduced motion, srgb) réduit l'empreinte mais rend le profil distinctif. Les utilisateurs qui reportent toutes les valeurs par défaut sont rares.
Tor Browser standardise de nombreux valeurs CSS mais cela crée une empreinte Tor identifiable.
Le défi est d'assurer que les media features, matchMedia() et propriétés DOM (ex. screen.colorDepth) renvoient des valeurs cohérentes depuis une source unique.
Approche de BotBrowser au niveau moteur
BotBrowser contrôle les media features au niveau du moteur Chromium, garantissant la cohérence entre CSS et JavaScript.
Source unifiée de signaux
Au chargement d'un profil, toutes les valeurs d'affichage et de préférences proviennent du profil :
- Schéma de couleur contrôlé par
--bot-config-color-scheme. Les règles@mediaetmatchMedia()retournent la même valeur. - Dimensions d'écran issues du profil ;
@media (width: ...)etscreen.widthcorrespondent. - Device pixel ratio du profil influence
@media (resolution: ...)etdevicePixelRatio. - Profondeur de couleur du profil contrôle
@media (color: ...)etscreen.colorDepth. - Pointer et hover correspondent au type d'appareil du profil.
Alignement CSS-JS
BotBrowser garantit qu'il n'existe aucun écart entre ce que voient les règles CSS @media et ce que rapportent les APIs JavaScript, car les deux lisent la même configuration à l'échelle du moteur.
Cela couvre :
@media (prefers-color-scheme: dark)↔matchMedia('(prefers-color-scheme: dark)')@media (min-resolution: 2dppx)↔window.devicePixelRatio@media (pointer: fine)↔matchMedia('(pointer: fine)')@media (color-gamut: p3)↔matchMedia('(color-gamut: p3)')
Chargement conditionnel de ressources
Puisque l'évaluation des media features se fait au niveau du moteur, même le fingerprinting pur CSS (chargement conditionnel) renvoie des valeurs conformes au profil.
Cohérence cross-contexte
Les media features restent cohérentes dans :
- feuilles de style du document principal
- feuilles du Shadow DOM
matchMedia()depuis n'importe quel contexte JS- contenu d'iframe (same-origin et cross-origin)
- media queries d'impression
Configuration et usage
Chargement de base du profil
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Les signaux CSS sont configurés automatiquement depuis le profil.
Contrôle du schéma de couleur
# Forcer le mode clair
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=light
# Forcer le mode sombre
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=dark
Configuration d'affichage
# Utiliser les paramètres d'écran et de fenêtre du profil
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-screen=profile \
--bot-config-window=profile
# Désactiver l'override du device scale factor
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-disable-device-scale-factor=true
Intégration Playwright
const { chromium } = require('playwright');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-config-color-scheme=light',
'--bot-config-screen=profile',
'--bot-config-window=profile'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
const signals = await page.evaluate(() => ({
darkMode: window.matchMedia('(prefers-color-scheme: dark)').matches,
highDPI: window.matchMedia('(min-resolution: 2dppx)').matches,
finePointer: window.matchMedia('(pointer: fine)').matches,
hoverCapable: window.matchMedia('(hover: hover)').matches,
colorDepth: screen.colorDepth,
devicePixelRatio: window.devicePixelRatio
}));
console.log(signals);
Vérification
Cohérence CSS-JS. Pour chaque caractéristique, comparez la valeur évaluée par CSS avec la valeur rapportée par JavaScript. matchMedia('(prefers-color-scheme: dark)').matches doit correspondre au rendu.
Rendu du schéma de couleur. Visitez un site avec dark mode ; le rendu doit correspondre à --bot-config-color-scheme.
Cohérence DPI. Comparez window.devicePixelRatio avec matchMedia('(resolution: 2dppx)').matches.
Pointer & hover. Vérifiez que matchMedia('(pointer: fine)').matches renvoie la valeur attendue.
Stabilité entre sessions. Exécutez les mêmes vérifications avec le même profil; les valeurs doivent être identiques.
Bonnes pratiques
- Définir explicitement le schéma de couleur. Utilisez
--bot-config-color-scheme=lightoudark. - Faire correspondre pointer/hover au type d'appareil. Desktop ->
pointer: fine; mobile ->pointer: coarse. - Utiliser les paramètres d'affichage du profil.
--bot-config-screen=profileet--bot-config-window=profile. - Tester avec CSS et JS. Vérifiez
@mediaetmatchMedia()ensemble. - Prendre en compte l'impact du dark mode pour les captures. Pour comparaisons visuelles, gardez le schéma cohérent.
FAQ
Q : Les sites peuvent-ils me fingerprint sans JS uniquement via CSS ?
A : Oui. Le chargement conditionnel via @media peut extraire des valeurs sans JS. BotBrowser contrôle l'évaluation des media features au niveau du moteur, donc ces détections utilisent des valeurs contrôlées.
Q : prefers-reduced-motion affecte-t-il les animations ?
A : Oui. Quand prefers-reduced-motion: reduce est actif, les sites bien conçus réduisent ou suppriment les animations. Les profils BotBrowser définissent cette préférence selon l'appareil source.
Q : Combien de bits d'entropie fournissent les media features CSS ? A : Chaque feature apporte typiquement 1-3 bits. En combinant 15+ features, on peut atteindre 10-15 bits dans de bonnes conditions.
Q : BotBrowser gère-t-il forced-colors ?
A : Oui. forced-colors (mode High Contrast Windows) est contrôlé par le profil ; en standard on renvoie forced-colors: none.
Q : Qu'en est-il de dynamic-range ?
A : dynamic-range (standard ou high) indique la capacité HDR ; les profils incluent cette information.
Q : Les media features sont-elles cohérentes dans les iframes ? A : Oui. Le contrôle au niveau du moteur s'applique à tous les contextes de rendu, y compris les iframes same-origin et cross-origin.
Résumé
Les media features CSS forment une surface de fingerprinting indépendante de JavaScript qui révèle la configuration d'affichage, les préférences et les capacités d'interaction. BotBrowser contrôle ces features au niveau du moteur Chromium afin de garantir que @media, matchMedia() et les propriétés DOM renvoient des valeurs cohérentes dérivées du profil. Grâce à --bot-config-color-scheme et aux paramètres d'affichage pilotés par profil, BotBrowser comble l'écart entre ce que observe le CSS et ce que rapporte JavaScript.
Sujets connexes : What is Browser Fingerprinting, Screen and Window Protection, Font Fingerprint Protection, Navigator Property Protection.
title: "Coherence des signaux CSS avec BotBrowser" description: "Comment BotBrowser assure que les media queries CSS et les APIs JavaScript retournent des valeurs concordantes grace au controle de profil au niveau du moteur du navigateur." date: "2025-06-18" locale: fr category: fingerprint tags: ["css", "fingerprinting", "privacy", "color-depth", "media-queries"] published: true
Le risque pour la vie privee
Les media queries CSS exposent des informations sur l'appareil - profondeur de couleur, resolution d'ecran, preference de schema de couleurs, type de pointeur - sans executer de JavaScript. Un serveur peut detecter ces valeurs uniquement par le comportement de chargement des feuilles de style, rendant cette surface difficile a observer et controler.
Le defi critique : les resultats des media queries CSS doivent correspondre aux valeurs des APIs JavaScript. Les outils bases sur des extensions ne peuvent modifier que les valeurs de retour JavaScript tout en laissant l'evaluation des media queries CSS intacte, creant des ecarts detectables.
La solution BotBrowser
BotBrowser controle les signaux lies au CSS au niveau du moteur du navigateur. Lorsqu'un profil est charge, l'etat interne du navigateur est configure pour que toutes les media queries CSS et leurs equivalents JavaScript lisent depuis la meme source.
Configuration basee sur le profil
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Ce seul flag definit les proprietes d'ecran, la profondeur de couleur, le ratio de pixels de l'appareil et les valeurs des caracteristiques media. Les requetes CSS comme (color: 8), (prefers-color-scheme: light) et (pointer: fine) refletent toutes l'appareil cible du profil.
Pas d'ecart entre CSS et JS
Parce que BotBrowser modifie les donnees de plateforme sous-jacentes plutot que de patcher des APIs individuelles, il n'y a pas d'ecart entre ce que CSS evalue et ce que JavaScript rapporte.
Verification
Apres avoir charge un profil, verifiez l'alignement entre CSS et JavaScript :
const { chromium } = require('playwright-core');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
defaultViewport: null,
});
const page = await (await browser.newContext()).newPage();
const results = await page.evaluate(() => {
const cssColor = matchMedia('(color: 8)').matches;
const jsDepth = screen.colorDepth;
const cssWidth = matchMedia(`(device-width: ${screen.width}px)`).matches;
const cssPointer = matchMedia('(pointer: fine)').matches;
const touchPoints = navigator.maxTouchPoints;
return {
colorConsistent: cssColor === (jsDepth === 24),
widthConsistent: cssWidth,
pointerConsistent: cssPointer === (touchPoints === 0),
};
});
console.log('Coherence CSS/JS:', results);
// Toutes les valeurs doivent etre true
Verifications cles :
matchMedia('(color: 8)')correspond ascreen.colorDepthmatchMedia('(device-width: Xpx)')correspond ascreen.widthmatchMedia('(pointer: fine)')correspond anavigator.maxTouchPoints
Pour commencer
- Telechargez BotBrowser depuis GitHub
- Chargez un profil d'empreinte avec
--bot-profile - Definissez
defaultViewport: nulldans Playwright ou Puppeteer pour que le profil controle les dimensions - Verifiez la coherence CSS et JavaScript avec DevTools ou des outils de test