Отпечатки Canvas, WebGL и аудио: как вас выдает железо
Откуда берется разброс в трех самых распространенных аппаратных отпечатках, почему одна и та же машина выглядит иначе в другом браузере и почему расширения, добавляющие шум, обычно делают вас заметнее, а не наоборот. С замечанием о WebGPU.
5 мин чтения · Опубликовано 10 сентября 2026 г.
Попросите браузер нарисовать строку текста, отрендерить треугольник и обработать кусочек звука, который никто не услышит. Захешируйте результаты. Ничего из этого не требует запроса разрешения, пользователь ничего не замечает, а вместе эти три значения помещают вашу машину в очень узкую группу среди миллионов устройств. Механика здесь не таинственная, и в ней стоит разобраться.
Canvas: различия, которые можно нарисовать
Скрипты canvas-фингерпринтинга похожи друг на друга как близнецы. Создать невидимый <canvas>, написать фразу парой шрифтов (обычно что-нибудь с разнообразными глифами вроде «Cwm fjordbank glyphs vext quiz» плюс эмодзи для верности), наложить несколько полупрозрачных цветных прямоугольников и дуг, затем вызвать toDataURL(), чтобы получить PNG в base64, или getImageData(), чтобы прочитать сырые пиксели, — и захешировать результат.
Одинаковые команды рисования должны бы давать одинаковые пиксели. Не дают, потому что путь от команды до пикселя длинный:
- Растеризация шрифтов. Один и тот же файл шрифта проходит через DirectWrite в Windows, Core Text в macOS и FreeType в Linux, и каждый превращает кривые в пиксели по-своему.
- Сглаживание и субпиксельный рендеринг. Полупрозрачные пиксели на краях зависят от системных настроек, ориентации экрана и того, включен ли рендеринг в духе ClearType.
- GPU и драйвер. Браузеры отдают рисование на canvas видеокарте, а интерполяция дуг и округление в режимах смешивания едва заметно различаются между картами и версиями драйверов.
- Управление цветом. В некоторых конфигурациях цветовой профиль дисплея просачивается в вывод canvas.
Любое отдельное отличие в пикселе ничтожно, но хеш раздувает их все в совершенно другую строку. Хорошая новость — для трекера — в стабильности: та же машина в том же браузере рисует ровно ту же картинку сегодня и через месяц. Именно эта стабильность и позволяет использовать значение как идентификатор.
WebGL: пиксели плюс гора параметров
У WebGL-фингерпринтинга два слоя. Первый похож на canvas: отрендерить сцену с градиентами и вершинным шейдером, прочитать пиксели, захешировать. Компилятор шейдеров и точность вычислений с плавающей запятой на GPU добавляют еще один источник разброса.
Второй слой грубее. WebGL просто сообщает множество статических фактов. Расширение WEBGL_debug_renderer_info открывает немаскированные строки vendor и renderer — что-то вроде ANGLE (Apple, ANGLE Metal Renderer: Apple M2, Unspecified Version) или ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11). Дальше — список поддерживаемых расширений, всевозможные лимиты (максимальный размер текстуры, число вершинных атрибутов, сэмплов сглаживания) и форматы точности шейдеров. Суммарная энтропия очень высока; одна только строка renderer называет чип, графический бэкенд и примерно поколение драйвера.
Разработчики браузеров это знают. Safari и Firefox в некоторых конфигурациях огрубляют renderer до чего-то вроде «Apple GPU».
Аудио: отпечаток, который не услышать
Фингерпринтинг через AudioContext чаще всего неправильно понимают как «ему нужен микрофон». Не нужен. Скрипт строит сигнал в памяти с помощью OfflineAudioContext: осциллятор генерирует треугольную или синусоидальную волну, она проходит через DynamicsCompressorNode, несколько тысяч сэмплов рендерятся офлайн, и результат суммируется или хешируется. Беззвучно, за десятки миллисекунд.
Откуда разброс? Детали реализации плавающей запятой, DSP-библиотека браузера, конкретный алгоритм компрессора и округления в аудиостеке ОС. Код один и тот же, а Chrome и Firefox расходятся в нескольких знаках после запятой. Этого достаточно.
Почему одна и та же машина меняется вместе с браузером
Потому что каждая «последняя миля» из описанных выше реализована самим браузером. Chrome рисует 2D через Skia, а WebGL прогоняет через ANGLE в Direct3D 11 на Windows или Metal на macOS. У Firefox свой стек, у Safari — еще один. Движки текстового шейпинга и аудиобэкенды тоже разные. Так что отпечатки canvas, WebGL и аудио на самом деле идентифицируют связку «это железо + эта ОС + эта сборка браузера», а не железо само по себе.
По той же причине отпечатки часто меняются после крупного обновления браузера, и трекеры опираются на другие стабильные сигналы (экран, часовой пояс, шрифты), чтобы связать старый отпечаток с новым.
Почему расширения с добавлением шума часто вредят
Есть масса расширений в духе «Canvas Defender», которые вносят небольшие случайные искажения в пиксели перед тем, как toDataURL вернет результат, так что каждое чтение получается разным. Звучит разумно. Две проблемы.
Во-первых, настоящие браузеры стабильны. Если сайт рисует canvas дважды и получает два разных хеша, он сразу понимает, что у вас стоит инструмент искажения. В нашей оценке подлинности есть именно такая проверка: два рисунка не совпали — минус баллы. Такими инструментами пользуются немногие, поэтому сам по себе этот сигнал помещает вас в небольшую группу.
Во-вторых, если расширение вместо этого применяет фиксированное смещение (одно и то же каждый раз), ваш хеш становится значением, которого нет больше ни у кого в мире. Это уникальнее, чем значение без шума, которое хотя бы совпадало с несколькими тысячами одинаковых MacBook. Ровно противоположно цели.
Более зрелые подходы встроены в сами браузеры. privacy.resistFingerprinting в Firefox спрашивает разрешение перед чтением canvas и приводит параметры WebGL к типовым значениям, чтобы все, у кого включена эта настройка, выглядели одинаково. «Farbling» в Brave хитрее: искажения строятся на seed, выведенном из сайта и сессии, так что в пределах одного сайта отпечаток стабилен (нет предательского «мерцания»), а между сайтами различается (нет связывания).
На очереди WebGPU
Преемник WebGL, WebGPU, уже есть в Chrome; на момент написания Safari и Firefox догоняют. Информация об адаптере включает vendor, architecture, device и description, длинный список лимитов (максимальный размер буфера, размерности рабочих групп и т. д.) и опциональные возможности. Все это ближе к железу, чем аналоги в WebGL, а вычислительные шейдеры упрощают измерения, основанные на времени выполнения. Исследователи фингерпринтинга уже взяли его на вооружение как свежий источник. Наш отчет WebGL показывает информацию об адаптере WebGPU всегда, когда браузер его поддерживает, — можно увидеть, сколько он раскрывает.
Вопросы и ответы
Можно просто отключить canvas-фингерпринтинг? Можно, но сломается многое из того, что зависит от canvas (графики, редакторы изображений, часть CAPTCHA), а само «отключено» тоже обнаруживается. Практичный путь — resistFingerprinting в Firefox или Brave: согласиться на «выглядеть как толпа» вместо погони за «невидимостью».
Мой renderer WebGL показывает SwiftShader или llvmpipe. Что это значит? Браузер рендерит программно на CPU, без аппаратного ускорения. Настоящие десктопные браузеры так делают редко, виртуальные машины и headless-браузеры — сплошь и рядом, поэтому это считается сигналом бот-детекции.
На этом сайте мой хеш canvas «совпадает с M из последних N визитов». Большое M — это хорошо или плохо? Хорошо: вы похожи на многих других людей, и вас трудно выделить. M, равное 1, означает, что такого значения больше никто не выдал.