Retour au Blog
Empreinte

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, p3 ou rec2020.
  • monochrome — si l'appareil est monochrome et bits par pixel.

Préférences utilisateur :

  • prefers-color-scheme — préférence light ou dark.
  • 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.
  • orientationportrait ou landscape.

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, ou fine.
  • 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: coarse et hover: none, les desktops rapportent pointer: fine et hover: 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 @media et matchMedia() retournent la même valeur.
  • Dimensions d'écran issues du profil ; @media (width: ...) et screen.width correspondent.
  • Device pixel ratio du profil influence @media (resolution: ...) et devicePixelRatio.
  • Profondeur de couleur du profil contrôle @media (color: ...) et screen.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=light ou dark.
  • 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=profile et --bot-config-window=profile.
  • Tester avec CSS et JS. Vérifiez @media et matchMedia() 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 :

  1. matchMedia('(color: 8)') correspond a screen.colorDepth
  2. matchMedia('(device-width: Xpx)') correspond a screen.width
  3. matchMedia('(pointer: fine)') correspond a navigator.maxTouchPoints

Pour commencer

  1. Telechargez BotBrowser depuis GitHub
  2. Chargez un profil d'empreinte avec --bot-profile
  3. Definissez defaultViewport: null dans Playwright ou Puppeteer pour que le profil controle les dimensions
  4. Verifiez la coherence CSS et JavaScript avec DevTools ou des outils de test
#css#fingerprinting#media-queries#privacy