Отпечатки

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.

How a tracker turns Canvas into a stable device ID 1. Tracker script loads Bundled with ad / analytics SDK 2. Draw test pattern fillText, fillRect, gradients 3. Read pixels back toDataURL · getImageData 4. Hash pixel buffer SHA / MurmurHash / xxHash 5. POST to collector Beacon · navigator.sendBeacon 6. Match in device graph Cross-site identity link No prompt · no cookie · invisible to the user The full pipeline runs in under 50 ms inside any iframe. Clearing cookies, switching IP, or opening incognito does not change the hash.

Шаг сбора дёшев для трекера и полностью непрозрачен для посетителя. Дорогая часть живёт ниже по потоку в device graph: каждый сайт, который тянет тот же трекер, добавляет хеши, которые кластеризуются вместе, формируя профиль, следующий за пользователем через несвязанные домены. Поэтому задача защитника не в том, чтобы заблокировать вызов рисования, а в том, чтобы сделать отрендеренный вывод стабильным, реалистичным и согласованным со всем остальным, что сообщает браузер.

Почему результат Canvas различается на разных устройствах

Чтобы понять, почему Canvas даёт уникальный результат, полезно рассмотреть конвейер рендеринга:

  1. Растеризация шрифтов: разные операционные системы используют разные движки рендеринга текста (DirectWrite в Windows, Core Text в macOS, FreeType в Linux). Каждый движок формирует слегка отличающиеся контуры глифов, хинтинг и паттерны сглаживания.

  2. GPU-рендеринг: видеокарта и её драйверы влияют на обработку фигур, градиентов и операций композитинга. GPU от NVIDIA даёт чуть иной субпиксельный результат, чем AMD или Intel, даже для одних и тех же инструкций рисования.

  3. Управление цветом: операционные системы применяют разные цветовые профили и гамма-коррекцию. Градиент Canvas, отрисованный на калиброванной macOS-системе, отличается от того же градиента на стандартной установке Windows.

  4. Алгоритмы сглаживания: подходы к сглаживанию краёв различаются в зависимости от платформы, версии GPU-драйвера и настроек ОС. Эти различия достаточно малы, чтобы быть невидимыми для человеческого глаза, но достаточно велики, чтобы дать другой хеш при конвертации пиксельных данных в строку.

  5. Точность вычислений с плавающей точкой: различные архитектуры CPU могут по-разному обрабатывать математику с плавающей точкой, что влияет на рендеринг кривых Безье и вычисления трансформаций.

Когда пиксельный результат конвертируется в data URL или массив ImageData и хешируется, получается стабильный идентификатор, специфичный для устройства. Этот хеш не меняется между сессиями браузера, сохраняется после очистки кеша и остаётся одинаковым в окнах инкогнито.

Диаграмма ниже сравнивает три основные хост-платформы бок о бок. Каждый столбец показывает цепочку компонентов, вносящих вклад в финальный pixel buffer, и каждая цепочка производит разный хеш, даже когда JavaScript-вызовы рисования идентичны.

Same draw calls, three platforms, three hashes Windows host DirectWrite font engine ClearType + GDI hinting DirectX / ANGLE compositing Color profile + gamma Pixel hash A 2c6d03169685 macOS host Core Text font engine CoreGraphics smoothing Metal / IOSurface compositing ColorSync + Display P3 Pixel hash B 9c18bdc53952 Linux host FreeType font engine subpixel hinting · LCD filter ANGLE GL · Mesa compositor sRGB profile + display gamma Pixel hash C 4f72a18b6d4e Three different hashes from one identical drawCanvasTest() function. Trackers exploit exactly this divergence.

Почему распространённые инструменты конфиденциальности не справляются

Существует несколько подходов к противодействию 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 контролирует результат рендеринга на уровне движка браузера, создавая согласованные, реалистичные результаты, соответствующие полному профилю устройства.

Диаграмма ниже выкладывает четыре распространённые модели защиты против того типа инспекции, что выполняет современный детекционный скрипт. Каждый верхний слой обнаружим, потому что инспекция видит свидетельства того, что слой был вставлен. Рендеринг на уровне движка вообще не производит вставленного слоя.

Defense layers and what detection scripts see 1. Block Canvas API toDataURL throws or returns empty. Trackers see absence as a strong signal: very few real browsers do this. 2. Inject random noise per page load Hash changes on every reload. A hash that changes every visit is itself a fingerprint of a privacy tool, not stability. 3. Wrap CanvasRenderingContext2D in JS shim prototype.toString, descriptor checks, and toDataURL caller stack trace all expose the wrapper. Detectable. 4. Engine-level rendering control (BotBrowser) Pixels are produced inside the rendering pipeline that matches the loaded profile. No JS hook to detect. Hash is stable across runs, consistent with GPU strings, fonts, OS metadata, and audio surfaces. Higher-numbered layers leave fewer detectable artifacts. Only layer 4 produces output indistinguishable from a real device.

Как это работает

Когда вы загружаете профиль отпечатка, 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-защиты, показана ниже. Каждая строка представляет окружение, каждая колонка — свойство, которое должно выполняться. Защита, проваливающая любую ячейку матрицы, может быть обнаружена решительным фингерпринтером.

Cross-platform verification: same profile, identical hash Windows host running BotBrowser profile = mac_arm64.enc seed = 100 canvas hash 9c18bdc53952 webgl1: 0f9829ee244b webgl2: b879347569e8 UA: macOS · GPU: Apple macOS host running BotBrowser profile = mac_arm64.enc seed = 100 canvas hash 9c18bdc53952 webgl1: 0f9829ee244b webgl2: b879347569e8 UA: macOS · GPU: Apple Linux host (Xvfb) running BotBrowser profile = mac_arm64.enc seed = 100 canvas hash 9c18bdc53952 webgl1: 0f9829ee244b webgl2: b879347569e8 UA: macOS · GPU: Apple Same profile + same seed produces identical Canvas, WebGL1, and WebGL2 hashes regardless of host. That is the property no JavaScript shim can deliver.

Лучшие практики

  1. Всегда используйте полный профиль. Защита Canvas работает лучше всего, когда все сигналы согласованы. Загрузка профиля обеспечивает согласованность Canvas, WebGL, шрифтов и других сигналов с единой идентичностью устройства.

  2. Используйте детерминированный режим для тестирования. Флаг --bot-noise-seed обеспечивает повторяемые результаты, что необходимо для автоматизированного тестирования и CI-конвейеров.

  3. Не сочетайте расширения для модификации Canvas с BotBrowser. Браузерные расширения, модифицирующие Canvas, будут конфликтовать с управлением BotBrowser на уровне движка. BotBrowser обеспечивает защиту Canvas нативно.

  4. Согласуйте расположение прокси с вашим профилем. Профиль, настроенный для Windows-устройства в США, должен использовать прокси в США. Согласованность Canvas в сочетании с несоответствующей геолокацией ослабляет общую когерентность отпечатка.

  5. Записывайте 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 обеспечивает защиту конфиденциальности, которая является согласованной, реалистичной и практичной для повседневного использования.

#Canvas#fingerprinting#Html5#Privacy#Tracking

Переведите BotBrowser из исследований в продакшн

Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.