Последовательность CSS-сигналов с BotBrowser
Как media queries в CSS и такие параметры как глубина цвета и prefers-color-scheme создают сигналы отпечатка и как BotBrowser обеспечивает их согласованность.
Введение
CSS часто недооценивают как вектор для отпечатков, поскольку это прежде всего язык стилей. Однако media queries CSS открывают информацию о дисплее пользователя, его предпочтениях и возможностях браузера. Такие свойства, как prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution и forced-colors, раскрывают детали конфигурации устройства, которые вносят вклад в отпечаток. Особенность CSS-fingerprinting в том, что он работает без JavaScript: продуманная таблица стилей может извлечь информацию через условную загрузку ресурсов, оставаясь незаметной для средств защиты на стороне скриптов. В этой статье объясняется, как CSS-сигналы способствуют отпечатку и как BotBrowser гарантирует, что media queries, вызовы matchMedia() и связанные API возвращают согласованные значения из профиля.
Влияние на приватность
CSS-fingerprinting привлек внимание исследователей приватности, потому что он оперирует на другом уровне по сравнению с JavaScript-fingerprinting. Исследования показали, что при одновременном опросе 15+ медиахарактеристик CSS-особенности сами по себе могли отличать примерно 30% пользователей. В сочетании с JavaScript-определениями (которые должны совпадать с CSS-значениями) вероятность идентификации значительно растёт.
Спецификация W3C Media Queries Level 5 признаёт потенциал медиахарактеристик для отпечатков. Такие характеристики как prefers-color-scheme, prefers-contrast, prefers-reduced-motion и prefers-reduced-data указывают на пользовательские предпочтения, которые варьируются в популяции. Одиночная характеристика обычно имеет низкую энтропию (обычно бинарную или несколько значений), но комбинация многих характеристик создаёт значимый отпечаток.
CSS-fingerprinting особенно опасен тем, что может работать без выполнения JavaScript. Условно загружаемый пиксель отслеживания через @media сообщает серверу о конфигурации дисплея просто по запросу. Это значит, что даже пользователи, полностью блокирующие JS, могут частично подвергаться fingerprinting'у через CSS.
Технический фон
Медиахарактеристики CSS, важные для fingerprinting
Media queries CSS проверяют условия среды пользователя. Ниже перечислены наиболее релевантные характеристики:
Свойства дисплея:
resolution/min-resolution/max-resolution— плотность пикселей (dpi или dppx).color— число бит на компонент цвета.color-index— число цветов в LUT.color-gamut— приблизительный гамут:srgb,p3илиrec2020.monochrome— монохромный ли дисплей и битность.
Предпочтения пользователя:
prefers-color-scheme—lightилиdark.prefers-reduced-motion— запрос на уменьшение анимации.prefers-contrast— запрос на высокий/низкий контраст.prefers-reduced-transparency— предпочитаемое уменьшение прозрачности.forced-colors— режим принудительных цветов (Windows High Contrast).
Viewport и дисплей:
width/height— размеры viewport.device-width/device-height— размеры экрана (deprecated, но поддерживаются).aspect-ratio— соотношение сторон.orientation—portraitилиlandscape.
Взаимодействие:
hover— может ли основной указатель навешивать hover.any-hover— может ли любой указатель навешивать hover.pointer— точность указателя:none,coarseилиfine.any-pointer— есть ли вообще доступный указатель.
Как работает CSS-fingerprinting
CSS-fingerprinting может выполняться двумя способами.
Через JavaScript: Используется window.matchMedia() для программной проверки 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;
Чистый CSS (без JS): Условная загрузка ресурсов:
@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'); }
}
Сервер определяет предпочтение по запрошенному URL. Комбинация условий позволяет извлечь десятки бинарных сигналов с помощью только CSS.
Почему CSS-сигналы отличаются
Значения медиахарактеристик зависят от:
- Оборудования. Возможности монитора определяют гамут, глубину цвета и разрешение.
- Настроек ОС. Тёмная тема, высокий контраст, уменьшение анимации — системные настройки.
- Конфигурации браузера. Некоторые браузеры переопределяют системные предпочтения. Режим инкогнито может менять значения.
- Типа устройства. Сенсорные устройства сообщают
pointer: coarseиhover: none; десктопы —pointer: fineиhover: hover.
Проблема согласованности
Задача — не просто подменить одно поле, а сохранить согласованность множества сигналов одновременно. Если @media указывает на тёмную тему, но screen.colorDepth указывает на конфигурацию, связанную со светлой темой, возникает рассогласование — это само по себе сигнал.
Популярные подходы и их ограничения
Расширения браузера могут перехватывать matchMedia() но не могут изменить @media на уровне стилей. Страница может использовать чистый CSS, в то время как расширение правит только JS, что даёт обнаружимую несогласованность.
Отключение CSS ломает веб, поэтому не подходит.
Стандартизация предпочтений (всегда отдавать light, no reduced motion, srgb) снижает разнообразие, но делает профиль отличимым.
Tor Browser стандартизирует многие CSS-значения, уменьшая отпечатки, но создаёт распознаваемую Tor-подпись.
Задача — сделать так, чтобы media features, matchMedia() и свойства DOM (например screen.colorDepth) возвращали согласованные значения из единого источника.
Подход BotBrowser на уровне движка
BotBrowser управляет media features на уровне Chromium, обеспечивая согласованность CSS и JavaScript.
Единственный источник сигналов
При загрузке профиля все значения дисплея и предпочтений поступают из профиля:
- Схема цвета контролируется
--bot-config-color-scheme. И CSS@media, иmatchMedia()возвращают одно и то же. - Размеры экрана задаются профилем;
@media (width: ...)иscreen.widthсовпадают. - Device pixel ratio из профиля управляет
@media (resolution: ...)иdevicePixelRatio. - Глубина цвета из профиля управляет
@media (color: ...)иscreen.colorDepth. - Pointer/hover соответствуют типу устройства в профиле.
Выравнивание CSS и JS
BotBrowser гарантирует отсутствие расхождений между тем, что видит CSS, и тем, что сообщает JS, поскольку оба читают единую конфигурацию на уровне движка.
Примеры соответствия:
@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)')
Условная загрузка ресурсов
Поскольку media features контролируются на уровне движка, даже чистые CSS-детекторы вернут значения, соответствующие профилю. @media, решающий, загружать ли трекинг-пиксель, увидит схему из профиля, а не настройки хоста.
Согласованность в разных контекстах
Media features согласованы в:
- Основных стилях документа
- Shadow DOM
matchMedia()в любом JS-контексте- Контенте iframe (same-origin и cross-origin)
- Media queries для печати
Конфигурация и использование
Базовая загрузка профиля
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
CSS-сигналы настраиваются автоматически из профиля.
Управление схемой цвета
# Принудительно светлая тема
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=light
# Принудительно тёмная тема
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=dark
Настройки дисплея
# Использовать экранные и оконные настройки профиля
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-screen=profile \
--bot-config-window=profile
# Отключить переопределение device scale factor
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-disable-device-scale-factor=true
Интеграция 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);
Верификация
Согласованность CSS-JS. Для каждой медиахарактеристики сравните значение, вычисленное CSS, со значением, которое возвращает JavaScript. matchMedia('(prefers-color-scheme: dark)').matches должно соответствовать наблюдаемому рендеру.
Рендер схемы цвета. Посетите сайт с поддержкой dark mode — рендер должен соответствовать --bot-config-color-scheme.
Согласованность DPI. Сравните window.devicePixelRatio и matchMedia('(resolution: 2dppx)').matches.
Pointer и hover. Убедитесь, что matchMedia('(pointer: fine)').matches возвращает ожидаемое значение для профиля.
Стабильность между сессиями. Повторные проверки с тем же профилем должны давать одинаковые результаты.
Рекомендации
- Явно задавайте схему цвета. Используйте
--bot-config-color-scheme=lightилиdark. - Сопоставляйте pointer/hover с типом устройства. Desktop →
pointer: fine; mobile →pointer: coarse. - Используйте настройки экрана из профиля.
--bot-config-screen=profileи--bot-config-window=profile. - Тестируйте через CSS и JS. Проверяйте
@mediaиmatchMedia()одновременно. - Учитывайте влияние dark mode на скриншоты. Для визуального сравнения держите схему постоянной.
FAQ
В: Могут ли сайты fingerprint'ить меня через CSS без JS?
О: Да. Условная загрузка ресурсов через @media позволяет извлечь значения без JS. BotBrowser контролирует оценку media features на уровне движка, поэтому такие методы используют контролируемые значения.
В: Влияет ли prefers-reduced-motion на анимации?
О: Да. При prefers-reduced-motion: reduce сайты обычно уменьшают или отключают анимации. Профили BotBrowser содержат эту настройку в соответствии с устройством-источником.
В: Сколько бит энтропии дают медиахарактеристики CSS? О: Каждая характеристика обычно даёт 1–3 бита. Комбинируя 15+ характеристик, можно получить 10–15 бит в благоприятных условиях.
В: BotBrowser обрабатывает forced-colors?
О: Да. forced-colors (Windows High Contrast) контролируется профилем; стандартно возвращается forced-colors: none.
В: Что с dynamic-range?
О: dynamic-range (standard или high) означает HDR-возможности; профили включают эту информацию.
В: Последовательны ли медиахарактеристики в iframe? О: Да. Управление на уровне движка распространяется на все контексты рендера, включая iframes same-origin и cross-origin.
Резюме
Медиахарактеристики CSS дают поверхность для fingerprinting, независимую от JavaScript, раскрывая настройки экрана, предпочтения и возможности взаимодействия. BotBrowser контролирует эти характеристики на уровне Chromium, гарантируя, что @media, matchMedia() и DOM-свойства возвращают согласованные значения из профиля. С --bot-config-color-scheme и профильными настройками экрана BotBrowser устраняет разрыв между тем, что видит CSS, и тем, что сообщает JavaScript.
Похожие темы: What is Browser Fingerprinting, Screen and Window Protection, Font Fingerprint Protection, Navigator Property Protection.
title: "Согласованность CSS-сигналов с BotBrowser" description: "Как BotBrowser обеспечивает согласованность медиазапросов CSS и API JavaScript через управление профилями на уровне движка браузера." date: "2025-06-18" locale: ru category: fingerprint tags: ["css", "fingerprinting", "privacy", "color-depth", "media-queries"] published: true
Риск для конфиденциальности
Медиазапросы CSS раскрывают информацию об устройстве - глубину цвета, разрешение экрана, предпочтение цветовой схемы, тип указателя - без выполнения JavaScript. Сервер может определить эти значения исключительно через поведение загрузки таблиц стилей, что делает эту поверхность трудной для наблюдения и контроля.
Ключевая проблема: результаты медиазапросов CSS должны совпадать со значениями API JavaScript. Инструменты на основе расширений могут изменять только возвращаемые значения JavaScript, оставляя оценку медиазапросов CSS нетронутой, что создает обнаруживаемые расхождения.
Решение BotBrowser
BotBrowser контролирует CSS-сигналы на уровне движка браузера. При загрузке профиля внутреннее состояние браузера настраивается так, что все медиазапросы CSS и их JavaScript-аналоги читают из одного источника.
Конфигурация на основе профиля
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Этот единственный флаг устанавливает свойства экрана, глубину цвета, соотношение пикселей устройства и значения медиахарактеристик. CSS-запросы вроде (color: 8), (prefers-color-scheme: light) и (pointer: fine) отражают целевое устройство профиля.
Нет разрыва между CSS и JS
Поскольку BotBrowser изменяет базовые данные платформы, а не патчит отдельные API, нет разрыва между тем, что оценивает CSS, и тем, что сообщает JavaScript.
Верификация
После загрузки профиля проверьте согласованность CSS и 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('Согласованность CSS/JS:', results);
// Все значения должны быть true
Ключевые проверки:
matchMedia('(color: 8)')согласуется сscreen.colorDepthmatchMedia('(device-width: Xpx)')согласуется сscreen.widthmatchMedia('(pointer: fine)')согласуется сnavigator.maxTouchPoints
Начало работы
- Скачайте BotBrowser с GitHub
- Загрузите профиль отпечатка с помощью
--bot-profile - Установите
defaultViewport: nullв Playwright или Puppeteer, чтобы профиль контролировал размеры - Проверьте согласованность CSS и JavaScript с помощью DevTools или инструментов тестирования