Empreinte

Fingerprinting CSS : comment les styles vous suivent

Comment les media queries CSS comme color-depth et prefers-color-scheme créent des signaux d'empreinte, et comment assurer une identité CSS cohérente.

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.

Introduction

Le CSS est souvent négligé comme vecteur de fingerprinting car il est principalement un langage de mise en forme. Mais les media queries CSS exposent des informations sur l'affichage de l'utilisateur, ses préférences et les capacités du navigateur. Des propriétés comme prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution et forced-colors révèlent des détails de configuration de l'appareil qui contribuent à une empreinte. Ce qui rend le fingerprinting basé sur CSS particulièrement efficace est qu'il fonctionne sans JavaScript. Une feuille de style astucieusement construite peut extraire des informations sur l'appareil via le chargement conditionnel de ressources, le rendant invisible aux outils de confidentialité basés sur les scripts. Cet article explique comment les signaux CSS contribuent au fingerprinting et comment BotBrowser garantit que les media queries CSS, les appels JavaScript matchMedia() et les API associées retournent tous des valeurs cohérentes et pilotées par le profil.

Impact sur la vie privée

Le fingerprinting basé sur CSS a attiré l'attention de la communauté de recherche en confidentialité car il opère sur une couche différente du fingerprinting JavaScript. Une étude de 2021 de la TU Graz a démontré que les fonctionnalités des media CSS seules pouvaient distinguer environ 30 % des utilisateurs lorsque plus de 15 fonctionnalités média étaient interrogées simultanément. Combiné avec les propriétés accessibles par JavaScript (qui devraient concorder avec les valeurs CSS), le taux d'identification augmentait significativement.

La spécification W3C Media Queries Level 5 reconnaît le potentiel de fingerprinting des fonctionnalités média. La spécification note que des fonctionnalités comme prefers-color-scheme, prefers-contrast, prefers-reduced-motion et prefers-reduced-data révèlent chacune une préférence utilisateur qui varie dans la population. Bien que chaque fonctionnalité individuellement ait une faible entropie (typiquement un booléen ou quelques valeurs possibles), la combinaison de nombreuses fonctionnalités 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 via une règle @media informe le serveur de la configuration d'affichage de l'utilisateur par la requête seule. Cela signifie que même les utilisateurs qui bloquent complètement JavaScript peuvent être partiellement identifiés via CSS.

Contexte technique

Fonctionnalités média CSS pertinentes pour le fingerprinting

Les media queries CSS testent des conditions sur l'environnement de l'utilisateur. Les fonctionnalités suivantes sont les plus pertinentes pour le fingerprinting :

Propriétés d'affichage :

  • resolution / min-resolution / max-resolution - Densité de pixels de l'écran en dpi ou dppx.
  • color - Nombre de bits par composante de couleur.
  • color-index - Nombre de couleurs dans la table de consultation des couleurs de l'appareil.
  • color-gamut - Gamut de couleurs approximatif : srgb, p3 ou rec2020.
  • monochrome - Si l'appareil est monochrome et bits par pixel.

Préférences utilisateur :

  • prefers-color-scheme - Schéma de couleurs préféré de l'utilisateur : light ou dark.
  • prefers-reduced-motion - Si l'utilisateur a demandé une réduction du mouvement.
  • prefers-contrast - Si l'utilisateur a demandé un contraste élevé ou faible.
  • prefers-reduced-transparency - Si une transparence réduite est préférée.
  • forced-colors - Si le navigateur est en mode couleurs forcées (Contraste élevé Windows).

Viewport et affichage :

  • width / height - Dimensions du viewport.
  • device-width / device-height - Dimensions de l'écran (obsolète mais toujours supporté).
  • aspect-ratio - Rapport d'aspect du viewport.
  • orientation - Orientation du viewport : portrait ou landscape.

Interaction :

  • hover - Si le dispositif de pointage principal peut survoler.
  • any-hover - Si un dispositif de pointage peut survoler.
  • pointer - Précision du dispositif de pointage principal : none, coarse ou fine.
  • any-pointer - Précision de tout dispositif de pointage disponible.

Comment fonctionne le fingerprinting CSS

Le fingerprinting CSS peut être effectué par deux méthodes.

Basé sur JavaScript : En utilisant window.matchMedia() pour tester les media queries de manière programmatique :

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;

CSS pur (sans JavaScript) : En utilisant 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 schéma de couleurs de l'utilisateur en fonction de l'URL demandée. En chaînant plusieurs conditions, une feuille de fingerprinting purement CSS peut extraire des dizaines de signaux binaires.

Pourquoi les signaux CSS varient

Les valeurs des fonctionnalités média CSS dépendent de :

  • Le matériel. Les capacités du moniteur déterminent le gamut de couleurs, la profondeur de couleur et la résolution.
  • Les paramètres du système d'exploitation. Le mode sombre, le contraste élevé, le mouvement réduit et les paramètres d'accessibilité sont des préférences au niveau du système d'exploitation.
  • La configuration du navigateur. Certains navigateurs remplacent les préférences du système d'exploitation. Les modes de navigation privée peuvent modifier certaines valeurs.
  • Le type d'appareil. Les appareils tactiles rapportent pointer: coarse et hover: none. Les appareils de bureau rapportent pointer: fine et hover: hover.

Le problème de cohérence

Les valeurs CSS et JavaScript doivent concorder. Si window.matchMedia('(prefers-color-scheme: dark)').matches retourne true mais que screen.colorDepth suggère une configuration à thème clair, ou si les ressources chargées par CSS contredisent les valeurs rapportées par JavaScript, l'incohérence est elle-même un signal d'empreinte.

Approches de protection courantes et leurs limitations

Les extensions de navigateur peuvent intercepter window.matchMedia() mais ne peuvent pas modifier les règles @media CSS au niveau de la feuille de style. Une page peut utiliser du CSS pur pour extraire des valeurs tandis que l'extension ne contrôle que l'API JavaScript. Cela crée une incohérence détectable.

Désactiver le CSS casse l'ensemble du web. Ce n'est pas une approche viable.

Standardiser les préférences (toujours rapporter le mode clair, pas de mouvement réduit, gamut srgb) réduit l'empreinte mais crée un sous-ensemble distinctif. Un utilisateur qui rapporte exactement la valeur "par défaut" pour chaque préférence est rare et peut se démarquer.

Utiliser Tor Browser standardise de nombreuses valeurs CSS pour tous les utilisateurs. Mais cela crée une empreinte Tor Browser connue, qui est identifiable.

Le défi est de s'assurer que les fonctionnalités média CSS, les requêtes JavaScript matchMedia() et les propriétés DOM associées (comme screen.colorDepth) retournent toutes des valeurs cohérentes et contrôlées depuis une source unique.

L'approche au niveau du moteur de BotBrowser

BotBrowser contrôle les fonctionnalités média CSS au niveau du moteur de rendu Chromium, assurant la cohérence entre les API CSS et JavaScript.

Source de signal unifiée

Lorsqu'un profil d'empreinte est chargé, toutes les valeurs liées à l'affichage et aux préférences proviennent du profil :

  • Le schéma de couleurs est contrôlé par --bot-config-color-scheme. Les règles CSS @media (prefers-color-scheme: ...) et les requêtes JavaScript matchMedia() retournent la même valeur.
  • Les dimensions de l'écran proviennent de la configuration d'affichage du profil. CSS @media (width: ...) et JavaScript screen.width concordent.
  • Le ratio de pixels de l'appareil du profil contrôle à la fois CSS @media (resolution: ...) et JavaScript devicePixelRatio.
  • La profondeur de couleur du profil contrôle CSS @media (color: ...) et JavaScript screen.colorDepth.
  • Les capacités de pointeur et de survol correspondent au type d'appareil profilé. Un profil de bureau rapporte pointer: fine et hover: hover. Un profil mobile rapporte pointer: coarse et hover: none.

Alignement CSS-JavaScript

BotBrowser garantit qu'il n'y a aucun écart entre ce que les règles @media CSS voient et ce que les API JavaScript rapportent. C'est parce que l'évaluation des média CSS et l'accès aux propriétés JavaScript lisent tous deux la même configuration au niveau du moteur, qui est définie par le profil.

Cela s'applique à :

  • @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

Parce que les fonctionnalités média CSS sont contrôlées au niveau du moteur, même le fingerprinting purement CSS (via le chargement conditionnel de ressources) retourne des valeurs cohérentes avec le profil. Une règle @media qui charge un pixel de suivi basé sur le schéma de couleurs voit le schéma de couleurs du profil, pas la préférence de votre système.

Cohérence inter-contextes

Les fonctionnalités média CSS sont cohérentes à travers :

  • Les feuilles de style du document principal
  • Les feuilles de style du Shadow DOM
  • matchMedia() depuis tout contexte JavaScript
  • Le contenu des iframes (même origine et cross-origin)
  • Les requêtes de type média imprimé

Configuration et utilisation

Chargement de profil basique

chrome --bot-profile="/path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

Les signaux CSS sont configurés automatiquement à partir du profil.

Contrôle du schéma de couleurs

# 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 de l'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 le remplacement du facteur d'échelle de l'appareil
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');

// Vérifier la cohérence des signaux CSS
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);

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',
    '--bot-config-color-scheme=dark'
  ]
});

const page = await browser.newPage();
await page.goto('https://example.com');

Vérification

Cohérence CSS-JavaScript. Pour chaque fonctionnalité média, comparez la valeur évaluée par CSS avec la valeur rapportée par JavaScript. matchMedia('(prefers-color-scheme: dark)').matches devrait concorder avec le comportement de rendu que vous observez.

Rendu du schéma de couleurs. Visitez un site web avec support du mode sombre. Le rendu devrait correspondre au paramètre --bot-config-color-scheme (clair ou sombre).

Cohérence DPI. Comparez window.devicePixelRatio avec matchMedia('(resolution: 2dppx)').matches. Ils devraient concorder.

Pointeur et survol. Vérifiez que matchMedia('(pointer: fine)').matches retourne la valeur attendue pour votre profil (bureau vs. mobile).

Stabilité inter-sessions. Exécutez les mêmes vérifications de media query sur plusieurs sessions avec le même profil. Toutes les valeurs devraient être identiques.

Bonnes pratiques

  • Définissez le schéma de couleurs explicitement. Utilisez --bot-config-color-scheme=light ou dark pour contrôler la préférence. La valeur par défaut vient du profil, mais un contrôle explicite évite l'ambiguïté.
  • Faites correspondre le pointeur/survol au type d'appareil. Les profils de bureau devraient rapporter un pointeur fin et la capacité de survol. Les profils mobiles devraient rapporter un pointeur grossier et pas de survol. Les profils BotBrowser gèrent cela automatiquement.
  • Utilisez les paramètres d'affichage pilotés par le profil. --bot-config-screen=profile et --bot-config-window=profile garantissent que toutes les media queries liées aux dimensions correspondent au profil.
  • Testez avec le CSS et JavaScript. Vérifiez que les fonctionnalités média retournent des valeurs cohérentes via les règles @media (en vérifiant les styles rendus) et les appels API matchMedia().
  • Considérez l'impact du rendu en mode sombre. Les sites web s'affichent différemment en mode sombre. Si votre cas d'utilisation implique des captures d'écran ou des comparaisons visuelles, assurez-vous que le schéma de couleurs est défini de manière cohérente.

FAQ

Q : Les sites web peuvent-ils me suivre uniquement via CSS, sans JavaScript ? R : Oui. Le chargement conditionnel de ressources CSS (règles @media qui déclenchent des requêtes d'URL) peut extraire les valeurs des fonctionnalités média sans JavaScript. BotBrowser protège contre cela car l'évaluation des média CSS utilise les mêmes valeurs contrôlées que les API JavaScript.

Q : Est-ce que prefers-reduced-motion affecte les animations web ? R : Oui. Lorsque prefers-reduced-motion: reduce est actif, les sites web bien conçus désactivent ou simplifient les animations. Les profils BotBrowser définissent cette préférence selon la configuration de l'appareil profilé.

Q : Combien de bits d'entropie les fonctionnalités média CSS fournissent-elles ? R : Chaque fonctionnalité fournit typiquement 1 à 3 bits (par ex., clair/sombre pour le schéma de couleurs, fin/grossier/aucun pour le pointeur). Combinées sur plus de 15 fonctionnalités, le total peut atteindre 10 à 15 bits dans des conditions favorables.

Q : BotBrowser gère-t-il la fonctionnalité média forced-colors ? R : Oui. La fonctionnalité forced-colors (qui indique le mode Contraste élevé de Windows) est contrôlée par le profil. Un profil standard rapporte forced-colors: none.

Q : Qu'en est-il de la fonctionnalité média dynamic-range ? R : La fonctionnalité dynamic-range (standard ou high) indique la capacité d'affichage HDR. Les profils BotBrowser incluent cette information selon l'appareil profilé.

Q : Les fonctionnalités média CSS sont-elles cohérentes dans les iframes ? R : Oui. Le contrôle au niveau du moteur de BotBrowser s'applique à tous les contextes de rendu, y compris les iframes same-origin et cross-origin. Les fonctionnalités média sont cohérentes dans tous les cadres.

Résumé

Les fonctionnalités média CSS fournissent une surface de fingerprinting qui opère indépendamment du JavaScript et révèle la configuration d'affichage, les préférences utilisateur et les capacités d'interaction. BotBrowser contrôle toutes les fonctionnalités média CSS au niveau du moteur Chromium, garantissant que les règles @media, les requêtes matchMedia() et les propriétés DOM associées retournent toutes des valeurs cohérentes dérivées du profil chargé. Avec --bot-config-color-scheme pour le contrôle des préférences et les paramètres d'affichage pilotés par le profil, BotBrowser élimine l'écart entre les valeurs observées par CSS et rapportées par JavaScript.

Pour les sujets connexes, consultez Qu'est-ce que le Browser Fingerprinting, Protection de l'écran et de la fenêtre, Protection de l'empreinte des polices et Protection des propriétés Navigator.

#Css#fingerprinting#Media-Queries#Privacy

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.