Canvas-фингерпринтинг: принцип работы и защита
Узнайте, как фингерпринтинг через HTML5 Canvas отслеживает пользователей по уникальным паттернам рендеринга, и познакомьтесь с методами защиты на уровне движка.
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Что такое Canvas-фингерпринтинг?
Элемент HTML5 Canvas был создан для рисования графики, построения диаграмм и создания интерактивных визуализаций в браузере. Это один из наиболее широко используемых веб-API, который лежит в основе информационных панелей, браузерных игр и многого другого.
Однако у Canvas есть побочный эффект: когда браузер отрисовывает текст или фигуры на элементе Canvas, точный попиксельный результат зависит от GPU устройства, графических драйверов, композитинга операционной системы, движка рендеринга шрифтов и реализации сглаживания. Это значит, что два разных компьютера, выполняющих одни и те же инструкции Canvas, дадут слегка разные пиксельные данные.
Эти отклонения постоянны и воспроизводимы на одном и том же устройстве, что делает их стабильным сигналом для идентификации браузеров. Согласно исследованию Web Transparency and Accountability Project Принстонского университета, Canvas-фингерпринтинг был обнаружен на более чем 5% из 100 000 самых популярных сайтов ещё в 2014 году, и с тех пор его распространённость только выросла. Исследование 2020 года, опубликованное на USENIX Security Symposium, показало, что Canvas-фингерпринтинг позволяет различать устройства с точностью свыше 99% в сочетании с другими сигналами браузера.
Тревожным является то, что Canvas-фингерпринтинг не требует никаких разрешений, не сохраняет данные на устройстве и невидим для пользователей. Нет ни запроса, ни баннера о cookies, ни встроенного механизма отказа в браузерах.
Поток сбора, который запускают трекеры, короткий, тихий и переиспользуется на миллионах страниц. Диаграмма ниже прослеживает, что происходит между моментом попадания tracker-скрипта на страницу и тем, как стабильный идентификатор оказывается в базе данных device-graph.
Шаг сбора дёшев для трекера и полностью непрозрачен для посетителя. Дорогая часть живёт ниже по потоку в device graph: каждый сайт, который тянет тот же трекер, добавляет хеши, которые кластеризуются вместе, формируя профиль, следующий за пользователем через несвязанные домены. Поэтому задача защитника не в том, чтобы заблокировать вызов рисования, а в том, чтобы сделать отрендеренный вывод стабильным, реалистичным и согласованным со всем остальным, что сообщает браузер.
Почему результат Canvas различается на разных устройствах
Чтобы понять, почему Canvas даёт уникальный результат, полезно рассмотреть конвейер рендеринга:
-
Растеризация шрифтов: разные операционные системы используют разные движки рендеринга текста (DirectWrite в Windows, Core Text в macOS, FreeType в Linux). Каждый движок формирует слегка отличающиеся контуры глифов, хинтинг и паттерны сглаживания.
-
GPU-рендеринг: видеокарта и её драйверы влияют на обработку фигур, градиентов и операций композитинга. GPU от NVIDIA даёт чуть иной субпиксельный результат, чем AMD или Intel, даже для одних и тех же инструкций рисования.
-
Управление цветом: операционные системы применяют разные цветовые профили и гамма-коррекцию. Градиент Canvas, отрисованный на калиброванной macOS-системе, отличается от того же градиента на стандартной установке Windows.
-
Алгоритмы сглаживания: подходы к сглаживанию краёв различаются в зависимости от платформы, версии GPU-драйвера и настроек ОС. Эти различия достаточно малы, чтобы быть невидимыми для человеческого глаза, но достаточно велики, чтобы дать другой хеш при конвертации пиксельных данных в строку.
-
Точность вычислений с плавающей точкой: различные архитектуры CPU могут по-разному обрабатывать математику с плавающей точкой, что влияет на рендеринг кривых Безье и вычисления трансформаций.
Когда пиксельный результат конвертируется в data URL или массив ImageData и хешируется, получается стабильный идентификатор, специфичный для устройства. Этот хеш не меняется между сессиями браузера, сохраняется после очистки кеша и остаётся одинаковым в окнах инкогнито.
Диаграмма ниже сравнивает три основные хост-платформы бок о бок. Каждый столбец показывает цепочку компонентов, вносящих вклад в финальный pixel buffer, и каждая цепочка производит разный хеш, даже когда JavaScript-вызовы рисования идентичны.
Почему распространённые инструменты конфиденциальности не справляются
Существует несколько подходов к противодействию Canvas-фингерпринтингу, но каждый имеет существенные ограничения:
VPN и прокси-серверы
VPN меняет ваш IP-адрес, но никак не влияет на результат Canvas. Canvas-фингерпринтинг работает исключительно внутри движка рендеринга браузера и не имеет отношения к сетевому трафику. Два устройства за одним VPN всё равно дают совершенно разные Canvas-отпечатки.
Режим инкогнито / приватный просмотр
Режимы приватного просмотра очищают cookies, историю и локальное хранилище по завершении сессии. Они никак не модифицируют конвейер рендеринга Canvas. Ваш Canvas-отпечаток в режиме инкогнито идентичен отпечатку в обычном окне.
Браузерные расширения
Расширения, которые блокируют или модифицируют доступ к Canvas, сталкиваются с фундаментальной проблемой: они работают на уровне JavaScript API, а не на уровне рендеринга. Распространённые подходы включают:
- Полная блокировка Canvas: это легко обнаружить, потому что сайты могут проверить, возвращают ли операции Canvas пустые или ошибочные результаты. Заблокированный Canvas сам по себе является характерным сигналом.
- Добавление случайного шума: внедрение случайных пикселей в результат Canvas меняет отпечаток при каждой загрузке страницы. Хотя это предотвращает стабильное отслеживание, создаётся новая проблема: отпечаток, который меняется каждый раз, сам по себе является сильным сигналом использования инструментов конфиденциальности.
- Возврат подменённых данных: замена результата Canvas заранее вычисленными данными ломает сайты, которые используют Canvas для легитимных целей (диаграммы, CAPTCHA, карты), и часто даёт результат, не соответствующий другим сигналам браузера.
Основная проблема в том, что расширения могут перехватывать вызовы API, но не могут контролировать сам конвейер рендеринга. Это означает, что любая их модификация по своей сути обнаружима через проверки согласованности между тем, что браузер сообщает, и тем, что он реально рендерит.
Рандомизация на уровне браузера
Некоторые браузеры реализуют рандомизацию Canvas (например, функция Canvas noise в Brave). Она добавляет небольшие случайные возмущения к результату Canvas для каждого источника. Хотя это лучше подходов на базе расширений, рандомизация всё же имеет компромиссы:
- Сам паттерн шума можно проанализировать на статистические свойства, отличающиеся от реальной вариации устройства
- Рандомизированный результат может быть несогласован с сигналами GPU, шрифтов и ОС браузера
- Некоторые реализации рандомизируют только определённые операции Canvas, оставляя другие как идентификаторы
Подход BotBrowser на уровне движка
BotBrowser использует принципиально иной подход. Вместо блокировки, рандомизации или перехвата Canvas на уровне API, BotBrowser контролирует результат рендеринга на уровне движка браузера, создавая согласованные, реалистичные результаты, соответствующие полному профилю устройства.
Диаграмма ниже выкладывает четыре распространённые модели защиты против того типа инспекции, что выполняет современный детекционный скрипт. Каждый верхний слой обнаружим, потому что инспекция видит свидетельства того, что слой был вставлен. Рендеринг на уровне движка вообще не производит вставленного слоя.
Как это работает
Когда вы загружаете профиль отпечатка, BotBrowser настраивает весь конвейер рендеринга в соответствии с характеристиками устройства этого профиля. Результат Canvas не модифицируется после рендеринга. Вместо этого сам рендеринг даёт результат, соответствующий целевому устройству:
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Это означает:
- Хеш Canvas стабилен между сессиями, как и на реальном устройстве
- Результат согласован с GPU, ОС и шрифтовыми сигналами профиля
- Сайты, использующие Canvas для легитимных целей (диаграммы, карты, игры), работают нормально
- Нет перехватов или хуков на уровне API, которые можно было бы обнаружить
Детерминированный контроль шума
Для сценариев, требующих воспроизводимых результатов между тестовыми запусками, BotBrowser поддерживает сид шума:
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=12345
Один и тот же профиль и сид всегда дают идентичный результат Canvas, даже после перезагрузки системы и на разных хост-операционных системах. Это ценно для:
- Регрессионного тестирования, где результат Canvas нужно сравнивать между запусками
- Исследовательских сценариев, требующих воспроизводимых условий
- CI/CD-конвейеров, валидирующих согласованность отпечатков
Кроссплатформенная согласованность
Одна из важнейших возможностей BotBrowser для защиты Canvas - кроссплатформенная согласованность. Профиль Windows, загруженный на macOS или Linux, даёт результат Canvas, соответствующий характеристикам рендеринга Windows, определённым в профиле, а не конвейеру рендеринга хост-системы.
Это возможно только потому, что BotBrowser контролирует рендеринг на уровне движка. Подход на базе расширений или на уровне API не может переопределить фундаментальные различия рендеринга между операционными системами.
Запись Canvas-операций для аудита
Для исследователей конфиденциальности и разработчиков, которым нужно проверять поведение Canvas, BotBrowser может записывать все Canvas-операции:
chrome --bot-profile="/path/to/profile.enc" \
--bot-canvas-record-file="/path/to/canvas-log.json"
Это фиксирует каждый вызов Canvas API, его параметры и результат, предоставляя полный журнал аудита для анализа без необходимости внедрения кода.
Руководство по настройке
Базовая защита с Playwright
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
await page.goto('https://example.com');
// Canvas output will be consistent with the loaded profile
await browser.close();
})();
Детерминированный режим с Puppeteer
const puppeteer = require('puppeteer-core');
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-noise-seed=42',
],
headless: true,
defaultViewport: null,
});
В сочетании с другими средствами защиты
Canvas - один из множества сигналов. Для комплексной защиты сочетайте настройку Canvas с часовым поясом, локалью и прокси:
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=12345 \
--proxy-server="socks5://user:pass@proxy:1080" \
--bot-config-timezone="America/New_York" \
--bot-config-locale="en-US" \
--bot-config-languages="en-US,en"
Проверка
После запуска BotBrowser убедитесь, что защита Canvas работает корректно:
const page = await context.newPage();
// Render Canvas content and capture the hash
const hash1 = await page.evaluate(() => {
const c = document.createElement('canvas');
c.width = 200;
c.height = 50;
const ctx = c.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#333';
ctx.fillText('BotBrowser Canvas test', 2, 2);
ctx.fillStyle = 'rgba(0, 50, 255, 0.5)';
ctx.fillRect(50, 10, 100, 30);
return c.toDataURL();
});
// Reload and render again
await page.reload();
const hash2 = await page.evaluate(() => {
const c = document.createElement('canvas');
c.width = 200;
c.height = 50;
const ctx = c.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#333';
ctx.fillText('BotBrowser Canvas test', 2, 2);
ctx.fillStyle = 'rgba(0, 50, 255, 0.5)';
ctx.fillRect(50, 10, 100, 30);
return c.toDataURL();
});
console.log('Canvas output stable:', hash1 === hash2);
Вы также можете проверить результат с помощью публичных инструментов тестирования отпечатков, таких как CreepJS или BrowserLeaks. Они должны показать стабильный Canvas-хеш без аномалий.
Что проверять:
- Хеш Canvas остаётся одинаковым при перезагрузках страницы в рамках одной сессии
- Хеш Canvas совпадает между сессиями при использовании одного профиля и сида шума
- Разные профили дают разные Canvas-хеши
- Инструменты тестирования отпечатков не показывают предупреждений, связанных с Canvas
Матрица верификации, которую защитники используют для подтверждения работы Canvas-защиты, показана ниже. Каждая строка представляет окружение, каждая колонка — свойство, которое должно выполняться. Защита, проваливающая любую ячейку матрицы, может быть обнаружена решительным фингерпринтером.
Лучшие практики
-
Всегда используйте полный профиль. Защита Canvas работает лучше всего, когда все сигналы согласованы. Загрузка профиля обеспечивает согласованность Canvas, WebGL, шрифтов и других сигналов с единой идентичностью устройства.
-
Используйте детерминированный режим для тестирования. Флаг
--bot-noise-seedобеспечивает повторяемые результаты, что необходимо для автоматизированного тестирования и CI-конвейеров. -
Не сочетайте расширения для модификации Canvas с BotBrowser. Браузерные расширения, модифицирующие Canvas, будут конфликтовать с управлением BotBrowser на уровне движка. BotBrowser обеспечивает защиту Canvas нативно.
-
Согласуйте расположение прокси с вашим профилем. Профиль, настроенный для Windows-устройства в США, должен использовать прокси в США. Согласованность Canvas в сочетании с несоответствующей геолокацией ослабляет общую когерентность отпечатка.
-
Записывайте Canvas-операции для аудита. Используйте
--bot-canvas-record-fileво время разработки, чтобы проверить, какие Canvas-вызовы выполняет целевой сайт, и убедиться, что BotBrowser корректно их обрабатывает.
Часто задаваемые вопросы
Работает ли Canvas-фингерпринтинг в режиме инкогнито?
Да. Режим инкогнито не изменяет конвейер рендеринга браузера. Ваш Canvas-отпечаток идентичен в обычном окне и в окне инкогнито.
Могут ли сайты определить, что Canvas защищён?
Если защита работает путём блокировки или рандомизации Canvas, то да - несогласованность или отсутствие данных Canvas само по себе является сигналом. BotBrowser решает эту проблему, создавая реалистичный, согласованный результат через движок рендеринга, а не перехватывая вызовы API.
Влияет ли защита Canvas в BotBrowser на функциональность сайтов?
Нет. Поскольку BotBrowser контролирует конвейер рендеринга, а не блокирует вызовы API, все функции, зависящие от Canvas (диаграммы, карты, игры, CAPTCHA), работают нормально.
Сколько уникальных Canvas-отпечатков может создать BotBrowser?
Каждый профиль отпечатка генерирует уникальный Canvas-хеш. BotBrowser предоставляет сотни профилей, а корпоративные пользователи могут генерировать пользовательские профили для конкретных конфигураций устройств.
Работает ли защита Canvas на всех платформах?
Да. BotBrowser поддерживает Windows, macOS и Linux в качестве хост-операционных систем и может эмулировать Canvas-результат для любой поддерживаемой целевой платформы независимо от хоста.
Каково влияние защиты Canvas на производительность?
Минимальное. Поскольку защита работает внутри движка рендеринга, а не через постобработку или перехват API, Canvas-операции выполняются с почти нативной скоростью.
Итоги
Canvas-фингерпринтинг - одна из наиболее распространённых и сложных для противодействия техник отслеживания в вебе. BotBrowser решает эту проблему на уровне источника, контролируя конвейер рендеринга на уровне движка браузера, создавая согласованный, реалистичный результат, соответствующий полным профилям устройств. В сочетании с защитой WebGL, управлением аудио-отпечатком и комплексным управлением профилями, BotBrowser обеспечивает защиту конфиденциальности, которая является согласованной, реалистичной и практичной для повседневного использования.
Похожие статьи
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.