Как работает отслеживание цифрового отпечатка изнутри
От TLS-рукопожатий до рендеринга canvas — как мы восстанавливаем цифровой отпечаток устройства по более чем 300 пассивным сигналам, не завися от сохранённого состояния.
Каждое устройство, подключающееся к интернету, оставляет след из технических артефактов — цифровой отпечаток. В tracio.ai мы восстанавливаем этот отпечаток по более чем 300 пассивным сигналам, собранным за одну загрузку страницы, при этом идентификация не зависит ни от cookie, ни от какого-либо другого постоянного хранилища на стороне клиента. Эта статья подробно объясняет, как именно устроен этот процесс.
Слой сбора сигналов
Когда наш JavaScript-агент загружается в браузере посетителя, он начинает собирать сигналы сразу по нескольким категориям одновременно. Рендеринг canvas, запросы параметров WebGL, обработка через AudioContext, перечисление шрифтов и чтение свойств navigator — всё выполняется параллельно, и у каждой пробы свой таймаут, так что медленная не задерживает остальные. Сколько занимает весь проход, зависит от устройства посетителя, а приведённые ниже числа — то, что мы измеряем на своём стенде.
Ключевая идея в том, что каждый сигнал фиксирует свой аспект аппаратного и программного стека устройства. Рендеринг canvas отражает GPU, драйвер и движок отрисовки шрифтов. Параметры WebGL раскрывают модель и возможности видеокарты. AudioContext выявляет различия в том, как аудио-DSP обрабатывает операции с плавающей точкой. Свойства navigator сообщают число ядер CPU, объём памяти, платформу и языковые настройки.
Наша команда измерила это на 2 миллиардах событий за прошлый месяц: медианное время сбора составило 38 мс, а 99-й перцентиль — 52 мс. Сначала мы действительно попробовали наивный подход — собирать сигналы последовательно. Он оказался в 40 раз медленнее. Параллельный сбор с ограничением по таймауту стал одним из первых архитектурных решений, которое мы приняли правильно.
TLS-фингерпринтинг: первый слой
Ещё до того, как наш JavaScript вообще выполнится, браузер уже раскрыл значимую информацию через TLS-рукопожатие. Сообщение Client Hello содержит наборы шифров, которые поддерживает браузер, используемые им TLS-расширения, предпочитаемые эллиптические кривые и принимаемые алгоритмы подписи. Эта информация определяется TLS-библиотекой браузера и существенно различается между семействами браузеров, версиями и операционными системами.
Мы снимаем этот TLS-отпечаток с помощью хеширования JA4 — современной замены JA3, дающей лучшую детализацию и стабильность между версиями. Один только хеш JA4 способен отличить Chrome от Firefox и Safari, а часто сужает идентификацию до конкретного диапазона версий браузера. В сочетании с нашими клиентскими сигналами он даёт слой перекрёстной проверки, который крайне трудно подделать.
Фингерпринтинг canvas и GPU
Фингерпринтинг canvas использует тот факт, что разные GPU отрисовывают одни и те же инструкции с едва заметными различиями на уровне пикселей. Canvas API позволяет нам отрисовать тщательно спроектированную сцену — конкретные текстовые строки в нескольких шрифтах, геометрические фигуры с определёнными координатами и градиенты с точными цветовыми переходами — а затем вычислить хеш от полученных пиксельных данных.
Различия в отрисовке возникают из-за вариаций в алгоритмах сглаживания, субпиксельном рендеринге, смешивании цветов и хинтинге шрифтов у разных моделей GPU и версий драйверов. Даже два устройства с одной и той же моделью GPU могут выдавать разный вывод canvas, если работают на разных версиях драйверов или операционных системах. Это делает хеш canvas одним из наших наиболее отличительных сигналов.
Аппаратное профилирование через WebGL
WebGL API раскрывает подробную информацию о графической подсистеме, выходящую далеко за пределы строк renderer и vendor. Мы запрашиваем максимальные размеры текстур, форматы точности шейдеров, поддерживаемые расширения, размеры вьюпорта и десятки других параметров, которые различаются у разных моделей GPU и конфигураций драйверов.
Сочетание этих параметров создаёт подробный аппаратный профиль. Устройство с NVIDIA RTX 4070, например, сообщит иные максимальные размеры текстур, иную точность шейдеров и иную поддержку расширений, чем устройство с AMD RX 7800 XT. Этот аппаратный профиль по своей природе стабилен — он не меняется при обновлениях браузера, только при изменениях оборудования или драйверов.
Фингерпринтинг обработки аудио
Web Audio API предоставляет ещё один аппаратно-зависимый источник сигналов. Мы создаём узел-осциллятор, подключаем его к динамическому компрессору и измеряем выходной буфер. Различия в точности вычислений с плавающей точкой, реализации DSP и алгоритмах ресемплинга у разного аудиооборудования и операционных систем дают измеримые вариации в выводе.
Аудиоотпечатки обладают умеренной уникальностью, но исключительной стабильностью. Конвейер обработки аудио редко меняется, если только пользователь не сменит аудиооборудование или не переустановит операционную систему. Это делает аудиосигналы ценными опорными точками в нашей многоуровневой системе идентификации.
Слияние сигналов и разрешение идентичности
Сырые сигналы шифруются и передаются на наш сервер, где движок идентификации устройств обрабатывает их через трёхуровневую систему хеширования. Аппаратные сигналы (canvas, WebGL, аудио) образуют Уровень 1 — стабильное ядро идентичности. Сигналы уровня браузера (детектирование возможностей, свойства CSS, медиавозможности) образуют Уровень 2, который обрабатывается через сопоставление между сессиями, чтобы учитывать ожидаемый дрейф от обновлений браузера. Изменчивые сигналы (user agent, часовой пояс, язык) образуют Уровень 3, внося вклад в оценку уверенности без влияния на решения об идентичности.
Алгоритм слияния взвешивает каждый сигнал по его уникальности и стабильности. Совпадение по редкому хешу canvas несёт куда больший вес, чем совпадение по распространённому разрешению экрана. Такой взвешенный подход гарантирует, что идентификация остаётся точной, даже когда часть сигналов меняется.
Что мы храним и почему идентификация от этого не зависит
Критически важный принцип проектирования нашей системы в том, что идентификация не зависит от хранилища на стороне клиента. Идентификатор посетителя выводится из присущих устройству характеристик — оборудования, программного стека, сетевой конфигурации, — и именно поэтому идентификация переживает очистку cookie, режим инкогнито и даже переустановку браузера.
Это утверждение о зависимости, а не о воздержании, и разницу стоит проговорить прямо. Одну cookie первой стороны мы всё-таки ставим: _vid_t с непрозрачным идентификатором и сроком жизни 365 дней, и то же значение дублируем в localStorage. Чего мы не делаем: не ставим сторонние cookie, не пишем ничего, что работало бы между сайтами, и не читаем историю посещений, данные форм или IndexedDB. Эта cookie существует потому, что она — самый дешёвый из возможных ответов на вопрос «видели ли мы этот браузер раньше»: если она уцелела, совпадение мгновенное и достоверное. Если не уцелела, ничего не ломается: сигналы устройства восстанавливают идентификатор сами, с чуть меньшей уверенностью. Посетителя, который стёр всё, мы всё равно узнаём; система, построенная только на хранилище, его бы потеряла.
Приватность на уровне архитектуры
Поскольку мы собираем только технические атрибуты браузера — без истории посещений, без данных форм, без личного контента — влияние на приватность минимально. Руководство W3C по фингерпринтингу описывает лучшие практики ответственного использования браузерных сигналов, и наша архитектура соответствует этим принципам. Обработка происходит в нашем управляемом облаке, с резидентностью данных в ЕС (Франкфурт). Такая архитектура делает соблюдение GDPR, CCPA и других норм о приватности простым.