CSS-фингерпринтинг: отслеживание через стили
Как CSS-медиазапросы вроде color-depth и prefers-color-scheme создают сигналы отпечатков, и как обеспечить согласованную CSS-идентичность.
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Введение
CSS часто упускают из виду как вектор фингерпринтинга, поскольку это в первую очередь язык стилизации. Однако CSS-медиазапросы раскрывают информацию о дисплее пользователя, его предпочтениях и возможностях браузера. Свойства вроде prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution и forced-colors выявляют детали конфигурации устройства, которые вносят вклад в отпечаток. Особенная эффективность CSS-фингерпринтинга состоит в том, что он работает без JavaScript. Грамотно составленная таблица стилей может извлечь информацию об устройстве через условную загрузку ресурсов, что делает его невидимым для средств защиты на основе скриптов. В этой статье объясняется, как CSS-сигналы участвуют в фингерпринтинге и как BotBrowser обеспечивает согласованность CSS-медиазапросов, JavaScript-вызовов matchMedia() и связанных API с данными из загруженного профиля.
Влияние на приватность
CSS-фингерпринтинг привлёк внимание сообщества исследователей приватности, поскольку он действует на другом уровне, чем JavaScript-фингерпринтинг. Исследование 2021 года из Грацского технического университета показало, что одни только CSS-медиафункции могут различить примерно 30% пользователей при одновременном запросе 15 и более медиафункций. В сочетании с доступными через JavaScript свойствами (которые должны совпадать с CSS-значениями) уровень идентификации значительно возрастает.
Спецификация W3C Media Queries Level 5 признаёт потенциал фингерпринтинга медиафункций. Спецификация отмечает, что такие функции, как prefers-color-scheme, prefers-contrast, prefers-reduced-motion и prefers-reduced-data, раскрывают пользовательские предпочтения, которые варьируются в популяции. Хотя каждая функция по отдельности имеет низкую энтропию (обычно булево значение или несколько возможных вариантов), комбинация множества функций создаёт значимый отпечаток.
CSS-фингерпринтинг особенно вызывает озабоченность, потому что может работать без выполнения JavaScript. Отслеживающий пиксель, загружаемый условно через правило @media, сообщает серверу о конфигурации дисплея пользователя через сам запрос. Это означает, что даже пользователи, полностью блокирующие JavaScript, могут быть частично отпечатаны через CSS.
Техническая основа
CSS-медиафункции, связанные с фингерпринтингом
CSS-медиазапросы проверяют условия среды пользователя. Следующие функции наиболее актуальны для фингерпринтинга:
Свойства дисплея:
resolution/min-resolution/max-resolution- плотность пикселей экрана в dpi или dppx.color- количество бит на цветовой компонент.color-index- количество цветов в цветовой таблице устройства.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- размеры экрана (устарели, но всё ещё поддерживаются).aspect-ratio- соотношение сторон viewport.orientation- ориентация viewport:portraitилиlandscape.
Взаимодействие:
hover- может ли основное указательное устройство наводиться.any-hover- может ли любое указательное устройство наводиться.pointer- точность основного указательного устройства:none,coarseилиfine.any-pointer- точность любого доступного указательного устройства.
Как работает CSS-фингерпринтинг
CSS-фингерпринтинг может выполняться двумя способами.
На основе JavaScript: использование window.matchMedia() для программного тестирования медиазапросов:
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 (без JavaScript): использование условной загрузки ресурсов:
@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-сигналы различаются
Значения CSS-медиафункций зависят от:
- Оборудования. Характеристики монитора определяют цветовой охват, глубину цвета и разрешение.
- Настроек ОС. Тёмный режим, высокий контраст, уменьшение анимаций и настройки доступности - это предпочтения уровня ОС.
- Конфигурации браузера. Некоторые браузеры переопределяют системные предпочтения. Режимы приватного просмотра могут изменять определённые значения.
- Типа устройства. Сенсорные устройства сообщают
pointer: coarseиhover: none. Десктопные устройства сообщаютpointer: fineиhover: hover.
Проблема согласованности
Значения CSS и JavaScript должны совпадать. Если window.matchMedia('(prefers-color-scheme: dark)').matches возвращает true, но screen.colorDepth предполагает конфигурацию для светлой темы, или если ресурсы, загруженные через CSS, противоречат значениям, полученным через JavaScript, само несоответствие становится сигналом отпечатка.
Распространённые подходы защиты и их ограничения
Расширения браузера могут перехватывать window.matchMedia(), но не могут изменить правила @media на уровне таблицы стилей. Страница может использовать чистый CSS для извлечения значений, пока расширение контролирует только JavaScript API. Это создаёт обнаруживаемое несоответствие.
Отключение CSS ломает весь веб. Это нежизнеспособный подход.
Стандартизация предпочтений (всегда сообщать светлый режим, без уменьшения анимаций, srgb-охват) уменьшает отпечаток, но создаёт отличительное подмножество. Пользователь, сообщающий точно «стандартное» значение для каждого предпочтения, встречается редко и может выделяться.
Использование Tor Browser стандартизирует многие CSS-значения для всех пользователей. Но это создаёт известный отпечаток Tor Browser, который идентифицируется.
Сложность состоит в обеспечении того, чтобы CSS-медиафункции, JavaScript-запросы matchMedia() и связанные свойства DOM (например, screen.colorDepth) возвращали согласованные, контролируемые значения из единого источника.
Подход BotBrowser на уровне движка
BotBrowser контролирует CSS-медиафункции на уровне движка рендеринга Chromium, обеспечивая согласованность между CSS и JavaScript API.
Единый источник сигналов
При загрузке профиля отпечатка все значения, связанные с дисплеем и предпочтениями, берутся из профиля:
- Цветовая схема контролируется через
--bot-config-color-scheme. Как правила CSS@media (prefers-color-scheme: ...), так и JavaScript-запросыmatchMedia()возвращают одинаковое значение. - Размеры экрана берутся из конфигурации дисплея профиля. CSS
@media (width: ...)и JavaScriptscreen.widthсогласованы. - Соотношение пикселей устройства из профиля контролирует как CSS
@media (resolution: ...), так и JavaScriptdevicePixelRatio. - Глубина цвета из профиля контролирует CSS
@media (color: ...)и JavaScriptscreen.colorDepth. - Pointer и hover соответствуют типу профилированного устройства. Десктопный профиль сообщает
pointer: fineиhover: hover. Мобильный профиль сообщаетpointer: coarseиhover: none.
Согласованность CSS-JavaScript
BotBrowser гарантирует отсутствие разрыва между тем, что видят правила CSS @media, и тем, что сообщают JavaScript API. Это возможно потому, что как оценка CSS-медиа, так и доступ к JavaScript-свойствам читают из одной конфигурации на уровне движка, задаваемой профилем.
Это относится к:
@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)')
Условная загрузка ресурсов
Поскольку CSS-медиафункции контролируются на уровне движка, даже чистый CSS-фингерпринтинг (через условную загрузку ресурсов) возвращает значения, согласованные с профилем. Правило @media, загружающее отслеживающий пиксель на основе цветовой схемы, видит цветовую схему профиля, а не вашу системную настройку.
Согласованность между контекстами
CSS-медиафункции согласованы в:
- Таблицах стилей основного документа
- Таблицах стилей Shadow DOM
matchMedia()из любого JavaScript-контекста- Содержимом iframe (same-origin и cross-origin)
- Запросах типа медиа для печати
Конфигурация и использование
Базовая загрузка профиля
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
# Отключение переопределения коэффициента масштабирования устройства
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');
// Проверка согласованности 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);
Интеграция с 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');
Верификация
Согласованность CSS-JavaScript. Для каждой медиафункции сравните значение, полученное через CSS, со значением, полученным через JavaScript. matchMedia('(prefers-color-scheme: dark)').matches должно совпадать с наблюдаемым поведением рендеринга.
Рендеринг цветовой схемы. Посетите веб-сайт с поддержкой тёмного режима. Рендеринг должен соответствовать настройке --bot-config-color-scheme (light или dark).
Согласованность DPI. Сравните window.devicePixelRatio с matchMedia('(resolution: 2dppx)').matches. Они должны совпадать.
Pointer и hover. Убедитесь, что matchMedia('(pointer: fine)').matches возвращает ожидаемое значение для вашего профиля (десктоп или мобильное устройство).
Стабильность между сессиями. Запустите те же проверки медиазапросов в нескольких сессиях с одним и тем же профилем. Все значения должны быть идентичны.
Лучшие практики
- Задавайте цветовую схему явно. Используйте
--bot-config-color-scheme=lightилиdarkдля управления предпочтением. Значение по умолчанию берётся из профиля, но явный контроль исключает неопределённость. - Сопоставляйте pointer/hover с типом устройства. Десктопные профили должны сообщать fine pointer и hover capability. Мобильные профили - coarse pointer и отсутствие hover. Профили BotBrowser обрабатывают это автоматически.
- Используйте настройки дисплея из профиля.
--bot-config-screen=profileи--bot-config-window=profileобеспечивают соответствие всех связанных с размерами медиазапросов профилю. - Тестируйте и через CSS, и через JavaScript. Проверяйте, что медиафункции возвращают согласованные значения как через правила
@media(проверяя применённые стили), так и через вызовы APImatchMedia(). - Учитывайте влияние тёмного режима на рендеринг. Веб-сайты отображаются по-разному в тёмном режиме. Если ваш сценарий включает скриншоты или визуальное сравнение, убедитесь, что цветовая схема задана единообразно.
FAQ
В: Могут ли веб-сайты определить мой отпечаток только через CSS, без JavaScript?
О: Да. Условная загрузка ресурсов CSS (правила @media, которые инициируют URL-запросы) может извлечь значения медиафункций без какого-либо JavaScript. BotBrowser защищает от этого, потому что оценка CSS-медиа использует те же контролируемые значения, что и JavaScript API.
В: Влияет ли prefers-reduced-motion на веб-анимации?
О: Да. Когда prefers-reduced-motion: reduce активен, корректно спроектированные веб-сайты отключают или упрощают анимации. Профили BotBrowser устанавливают это предпочтение на основе конфигурации профилированного устройства.
В: Сколько бит энтропии дают CSS-медиафункции? О: Каждая функция обычно даёт 1-3 бита (например, light/dark для цветовой схемы, fine/coarse/none для pointer). В совокупности по 15+ функциям общее количество может достигать 10-15 бит при благоприятных условиях.
В: Обрабатывает ли BotBrowser медиафункцию forced-colors?
О: Да. Функция forced-colors (указывающая на режим Windows High Contrast) контролируется профилем. Стандартный профиль сообщает forced-colors: none.
В: Как насчёт медиафункции dynamic-range?
О: Функция dynamic-range (standard или high) указывает на поддержку HDR-дисплея. Профили BotBrowser включают эту информацию на основе профилированного устройства.
В: Согласованы ли CSS-медиафункции в iframe? О: Да. Управление BotBrowser на уровне движка применяется ко всем контекстам рендеринга, включая same-origin и cross-origin iframe. Медиафункции согласованы во всех фреймах.
Итоги
CSS-медиафункции предоставляют поверхность для фингерпринтинга, которая действует независимо от JavaScript и раскрывает конфигурацию дисплея, пользовательские предпочтения и возможности взаимодействия. BotBrowser контролирует все CSS-медиафункции на уровне движка Chromium, обеспечивая согласованность правил @media, запросов matchMedia() и связанных свойств DOM с данными загруженного профиля. С помощью --bot-config-color-scheme для управления предпочтениями и настроек дисплея на основе профиля BotBrowser устраняет разрыв между значениями, наблюдаемыми CSS и сообщаемыми JavaScript.
По связанным темам смотрите Что такое фингерпринтинг браузера, Защита экрана и окна, Защита отпечатка шрифтов и Защита свойств Navigator.
Похожие статьи
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.