От давления к дистракции к ускорению
Помните большой шум вокруг третьесторонних куки? Он был настолько громким, что Евросоюз уже запустил одно из своих величайших изобретений — баннеры согласия.
Если ЕС движется быстрее, чем техкомпании, это может означать только одно: техкомпании просто ждут. А одна из них контролирует две трети рынка браузеров.
Какой был план?
Поаплодируем Google — крупнейшей рекламной компании на земле!
АКТ I. ДАВЛЕНИЕ — "ПРИВАТНОСТЬ ДЛЯ НАС ИМЕЕТ ПЕРВОСТЕПЕННОЕ ЗНАЧЕНИЕ ВО ВСЕМ, ЧТО МЫ ДЕЛАЕМ"
2019 год, куки всё ещё в тренде. Репутация испортилась, Safari и Firefox уже их блокируют.
Через год Google дал обещание: мы уничтожим куки! И установим новый, privacy-first порядок.
АКТ II. ОТВЛЕЧЕНИЕ — "ВМЕСТО УДАЛЕНИЯ THIRD-PARTY COOKIES МЫ ПРЕДСТАВИМ НОВЫЙ ОПЫТ"
Пять лет спустя: людей теперь занимают куда более серьёзные проблемы, чем куки, а решения, которые разработал Google (Privacy Sandbox), просто неудачны и вызвали антимонопольные беспокойства — никто их не использует.
"Знаешь что, давай оставим куки. Зато мы замаскируем твой IP-адрес!" (* но только в режиме инкогнито при условии аутентификации) (** в итоге они даже это не доставили)
АКТ III. УСКОРЕНИЕ — ТЕПЕРЬ ВЫ МОЖЕТЕ ИСПОЛЬЗОВАТЬ DEVICE FINGERPRINTING В НАШИХ РЕКЛАМНЫХ ПРОДУКТАХ
Появился способ получше узнать, кто есть кто!
Как работает fingerprinting
Ладно, давайте разберёмся по-технически.
Пользователь заходит на сайт. Браузер отправляет запрос серверу, сервер возвращает код для выполнения браузером.
Сам запрос уже раскрывает информацию о пользователе: какой браузер используется, на каком языке, какая ОС, какой IP-адрес. IP часто выдаёт геолокацию.
Затем код выполняется.
Мы добились большого прогресса в безопасности браузинга. Давно прошли времена, когда вирус можно было подхватить просто посетив сайт. Вопрос в том, как определяется безопасность. Общее согласие кончается на изоляции: код одного сайта не видит данные других сайтов и не может получить доступ к файлам или приложениям без разрешения. Chrome и Edge здесь и останавливаются. Safari (особенно на iOS/macOS 26+) и Firefox расширяют определение на приватность, но от fingerprinting они вас всё ещё не защищают полностью. Brave и Tor — лидеры по privacy-first подходу, с перспективным новичком Mullvad Browser (Mullvad, по мнению автора текста, один из лучших VPN-провайдеров).
Код выполняется на железе, которое можно измерить так, чтобы получить стабильные и уникальные показания. С этим мало что можно поделать, так что есть только два проверенных решения:
- добавлять немного шума. Это называется farbling, и именно это делает Brave, чтобы отпечаток был непоследовательным.
- сделать всё одинаковым всегда, чтобы нельзя было отличить одного юзера от другого. Этот подход используют Tor и Mullvad.
Создаём отпечаток
Есть два источника данных для отпечатка: сетевой запрос и окружение кода.
На уровне сети данные либо хрупкие, либо универсальные:
- IP-адрес. В идеальном сценарии, когда человек всегда использует один IP, этого достаточно. Но обычно люди много чего браузят на мобильных сетях, делят WiFi, используют VPN или их домашний IP меняется провайдером. Хрупко.
- заголовки типа
User-AgentилиAccept-Languageраскрывают браузер, ОС, версии и язык.
Когда код выполняется на девайсе, можно измерить характеристики его железа (без запроса разрешений!) — и они удивительно стабильны:
- GPU: поведение, вендор, драйвер
- CPU: поведение, вендор, число потоков
- размер памяти
- данные дисплея: разрешение, пиксельное соотношение, частота обновления
- обработка звука
- модель девайса
На уровне ПО: установленные шрифты, расширения, информация о системе…
Миллионы девайсов используют свежий Chrome, миллионы Macов имеют чип M4, миллионы браузеров говорят по-французски.
Но когда смотреть на девайсы, где свежий Chrome на французском на M4, число резко падает. Добавьте измерения железа — и оно становится практически уникальным.
Отпечаток не обязательно должен быть глобально уникален — достаточно уникальности в пределах вашей выборки.
Почтовый индекс (выведен из IP), дата рождения (раскрыта в какой-то соцсети) и пол (заполняется везде) вместе достаточны, чтобы идентифицировать более 60% американцев.
Всегда можно добавить ещё одну переменную, чтобы сузить пул кандидатов.
Информационная энтропия
Играли когда-то в Акинатора? Вы думаете о персонаже, джин задаёт примерно двадцать вопросов — и как-то угадывает. Вот что такое fingerprinting в двух словах, только браузер отвечает на вопросы за вас. Когда разберётесь с информационной энтропией, магия Акинатора превратится в простой трюк.
Упростим с игрой, где нужно угадать персонажа на доске через вопросы типа "Мой персонаж — мужчина?". Если ответ "да", и половина персонажей на доске — мужчины, теперь рассматриваются только половина всех кандидатов. Можно сказать, что ответ дал вам log₂(100 / 50) = log₂(2) = 1 бит информации, потому что пул сократился в два раза.
Биты, полученные из одного ответа, называют его surprisal: чем реже ответ, тем больше информации.
- черта, общая для 1 из 2 человек — 1 бит (мужчина),
- 1 из 8 — 3 бита (усы),
- 1 из 128 — 7 бит (один глаз).
Surprisal количественно оценивает ценность ответа, а энтропия — ценность вопроса. Если 1 человек из 128 одноглазый, вопрос про это даст "нет" 127 раз из 128.
| Ответ | Вероятность | Surprisal | Вклад в энтропию |
|---|---|---|---|
| Да | 1/128 | log₂(128 / 1) = 7 бит |
1/128 x 7 = ~0.055 |
| Нет | 127/128 | log₂(128 / 127) = ~0.0113 бит |
127/128 x 0.0113 = ~0.011 |
Суммируя вклад каждого возможного ответа, сам вопрос стоит примерно 0.066 бит энтропии — это среднее количество бит, которые вы получите от ответа.
Когда объединяют независимые черты, просто складывают биты или перемножают соотношения — мужчина с усами и одним глазом означает 11 бит, или 1 из 2048. Увы, как знал бы вам Томас Байес, в реальности ничего не так просто. Усы — уже сильный индикатор мужчины, и мужчина вероятнее потеряет глаз. Черты не независимы, поэтому биты не складываются прямо.
Несколько интересных применений этого типа рассуждений:
- В медицинской диагностике: позитивный результат от 99%-точного теста на болезнь, поражающую 0.01% населения, примерно в 100 раз более вероятно будет ошибкой, чем вы действительно болеете. Нужны дополнительные доказательства!
- В криптографии: пароль из четырёх случайных слов так же стойкий, как восемь случайных символов клавиатуры (но гораздо легче запомнить!)

- В криминалистике: выделить одного человека в городе миллион населением требует примерно 20 бит. Описание свидетеля, совпадающее с 1 человеком из 1000, даёт только 10 бит — остаётся тысяча подозреваемых.
Что я могу с этим сделать?
Протестировать браузер:
- coveryourtracks.eff.org показывает, насколько уникален отпечаток, с энтропией каждой измеренной точки данных.
Если используется Chrome — это как ходить с ID на лбу.
Safari и Firefox предлагают некоторую защиту, но продвинутые трекеры вас всё ещё идентифицируют.
Brave, Tor и Mullvad Browser — пока единственные крупные браузеры, которые реализовали продвинутую защиту от fingerprinting.
Если не хочется менять браузер — понятно. Автор текста большой фанат Arc, а его снимают с поддержки, и privacy-функции там так и не появятся. Есть расширения типа JShelter — они нарушают скрипты fingerprinting, перехватывая вызовы браузерного API. Но они и ломают некоторые сайты. Та же проблема с Resist Fingerprinting в Firefox.
Парадокс в том, что privacy-расширения делают вас более уникальным, потому что их используют немногие. Умный трекер может это обнаружить, игнорировать испорченные сигналы и сосредоточиться на неповреждённых.
Никакое расширение не сравнится с защитой на уровне движка, встроенной прямо в браузер. Если не хотите быть отслеживаемым — нужно взять на себя обязательство.
Методы на этой странице
Просто создаём хеш из нескольких измерений девайса. Если что-то изменится — хеш теперь другой. Профессиональные приложения куда сложнее и способны поддерживать идентификацию, даже если отдельные переменные меняются.
-
OfflineAudioContextРендерит короткий тон через компрессор без воспроизведения; крошечные различия в результате зависят от звукового движка браузера и CPU.
const off = new OfflineAudioContext(1, 5000, 44100); // … a 1 kHz triangle wave into a dynamics compressor … const data = (await Promise.race([off.startRendering(), timeout])).getChannelData(0); let sum = 0; for (let i = 4500; i < 5000; i++) sum += Math.abs(data[i]); return sum.toFixed(3); -
WebGLЧитает вендор и модель GPU (без версий), что поддерживают GPU и её драйвер, пиксели маленького отрисованного треугольника.
const gl = document.createElement('canvas').getContext('webgl'); const dbg = gl.getExtension('WEBGL_debug_renderer_info'); return gpuName(gl.getParameter(dbg ? dbg.UNMASKED_RENDERER_WEBGL : gl.RENDERER) || ''); // "ANGLE (Apple, ANGLE Metal Renderer: Apple M4, Unspecified Version)" -> "apple m4" // … return fnv1a(new TextEncoder().encode([...(gl.getSupportedExtensions() || []).sort(), ...limits, ...precision].join('|'))); // … gl.drawArrays(gl.TRIANGLES, 0, 3); gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, px); -
canvasРисует текст в нескольких шрифтах, эмодзи и градиент, затем читает пиксели; антиалиасинг и рендеринг шрифта зависят от ОС, GPU и шрифтов.
ctx.font = '15px "Times New Roman", serif'; ctx.fillText('Sphinx of black quartz 🦊', 4, 22); // … const data = ctx.getImageData(0, 0, 240, 60).data; -
IntlЧасовой пояс и региональные настройки даты/чисел; VPN меняет IP-геолокацию, но не часовой пояс.
const date = Intl.DateTimeFormat().resolvedOptions(); // … return [date.timeZone, date.locale, date.calendar, date.numberingSystem, hourCycle, (1234567.891).toLocaleString()].join('/'); -
navigatorКоличество ядер CPU, размер памяти (только Chrome) и язык браузера.
return [navigator.hardwareConcurrency, navigator.deviceMemory, navigator.language].join('/'); -
crypto.subtleХеширует все значения SHA-256, и хеш выбирает черту и животное для ника.
const digest = await crypto.subtle.digest('SHA-256', bytes); // … nickname: stranger || `${pick(TRAITS, hex, 0)} ${pick(ANIMALS, hex, 8)}`,