Назад в Центр знаний
Отпечатки

Фингерпринтинг Navigator: утечки браузера

Как значения navigator, такие как platform, hardwareConcurrency, deviceMemory, languages и userAgentData, образуют сигнал отпечатка и как проверить их согласованность.

BotBrowser Team

Документация

Нужна поддерживаемая продуктовая документация?

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

Страница может прочитать navigator.platform, navigator.hardwareConcurrency, navigator.deviceMemory, navigator.languages и navigator.userAgentData ещё до первого запроса разрешения, и скрипт, записавший все эти значения, получает компактное описание машины за запросом. BotBrowser загружает такие значения из одного профиля в контролируемый контекст, поэтому основной поток, Web Worker и заголовки Sec-CH-UA описывают одно и то же устройство. Далее объясняется, как эти значения складываются в сигнал отпечатка, где изменённое значение начинает противоречить соседним, и как проверить согласованность раньше, чем это сделает сайт.

Кратко

  • Значения navigator читаются без запроса разрешения и оцениваются в совокупности, поэтому обычное значение в необычной компании весит больше отдельной записи.
  • userAgent, platform, vendor, userAgentData и заголовок Sec-CH-UA дважды отвечают на одни и те же вопросы; если изменение затронуло только одно из них, остаётся видимое расхождение.
  • Правка в скрипте страницы не доходит ни до Web Worker, ни до заголовка запроса, потому что оба читают из другой области.
  • BotBrowser берёт значения navigator из загруженного профиля, --bot-network-info-override управляет navigator.connection, а смена профиля лучше исправления одного поля.

Содержание

Какие значения navigator образуют сигнал

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

Руководство W3C по снижению фингерпринтинга в веб-спецификациях описывает эту схему прямо. Каждая возможность браузера добавляет немного вариативности, которую может прочитать скрипт, и множество мелких различий вместе способны отличить браузеры друг от друга, даже если ни одно отдельное значение не выглядит необычным. Поэтому в разделах ниже нет фиксированной цифры уникальности для значений navigator. Насколько сочетание идентифицирует браузер, зависит от того, какие браузеры реально видит сайт, а число, измеренное на одной аудитории, нельзя переносить на другую.

Загруженный профиль питает основной поток, Web Worker и заголовки Sec-CH-UA, и все они сообщают одну и ту же платформу, число ядер, уровень памяти, языки и бренд. Ниже строка UA с macOS рядом со значением platform, которое всё ещё сообщает Win32, даёт несоответствие.

Схема показывает обе половины темы. Когда одно описание устройства питает все места, которые отвечают на вопросы о navigator, ответы совпадают. Когда изменено только одно значение, связанные с ним значения продолжают описывать исходное устройство, и расхождение само становится сигналом.

Значения идентичности: userAgent, platform и vendor

navigator.userAgent это самое старое и чаще всего читаемое значение. Оно содержит название браузера, версию и маркер операционной системы. Браузеры на основе Chromium теперь сокращают детали в этой строке: версия операционной системы и дополнительная версия браузера в ней больше не указываются, а более тонкие сведения перенесены в User-Agent Client Hints. navigator.platform это короткая строка вроде "Win32", "MacIntel" или "Linux x86_64". MDN помечает её как устаревшую, но современные браузеры всё ещё возвращают значение, а скрипты всё ещё его читают. navigator.vendor возвращает строку производителя, которая различается у разных семейств браузеров.

Эти три значения описывают одни и те же два факта: что это за браузер и под какой операционной системой он работает, поэтому скрипт может проверить, согласуются ли они между собой. Неизменённый браузер проходит такую проверку без усилий, потому что все значения берутся из одной установки. Изменённый браузер проходит её только в том случае, если все связанные значения изменены вместе.

Значения оборудования, языка и соединения

navigator.hardwareConcurrency возвращает число логических процессоров, доступных для выполнения потоков. Браузеры могут сообщать меньшее или округлённое число по сравнению с тем, что есть у машины на самом деле, поэтому относитесь к нему как к подсказке, зависящей от оборудования и браузера, а не как к точной инвентаризации. navigator.deviceMemory это приближённая оценка оперативной памяти устройства в гигабайтах. Оно существует только в браузерах на основе Chromium, доступно только в защищённых контекстах, а сообщаемое значение ограничено числом 8, так что машина с большим объёмом памяти всё равно сообщает 8. Оба значения можно прочитать как в Web Worker, так и на основной странице, и это важно для проверок, описанных далее в статье.

navigator.language возвращает предпочитаемый язык, а navigator.languages возвращает упорядоченный список предпочитаемых языков, например en-US, а затем en. Список и заголовок запроса Accept-Language обычно происходят из одной и той же настройки браузера, поэтому значение, которое читает страница, и значение, которое получает сервер, описывают одни и те же предпочтения. Необычно длинный, необычно короткий или маловероятный для указанного региона список упрощает отличение этого сочетания от других.

navigator.connection предоставляет effectiveType, downlink, rtt и saveData в браузерах на основе Chromium. Эти значения описывают состояние сети, а не оборудование, и соответствующие заголовки Client Hints могут передавать ту же информацию в запросах. Поддержка различается между браузерами, а показания могут меняться вместе с сетью, поэтому они ведут себя иначе, чем значения оборудования выше. Тем не менее они входят в ту же запись, которую собирает скрипт.

Client Hints и userAgentData

navigator.userAgentData это структурированный аналог строки User-Agent в браузерах на основе Chromium. Он напрямую предоставляет список брендов браузера, признак мобильного устройства и название платформы. Его метод getHighEntropyValues() по запросу возвращает больше подробностей, например версию платформы, архитектуру, разрядность, модель и полный список версий. Та же информация передаётся в заголовках запроса Sec-CH-UA. Список брендов, признак мобильного устройства и платформа отправляются по умолчанию, а значения с более высокой энтропией отправляются только после того, как сервер запросит их в заголовке ответа Accept-CH.

В итоге на вопросы об одном и том же браузере отвечают три места: строка User-Agent, объект userAgentData и заголовки Client Hints. Согласованный браузер даёт один и тот же ответ во всех трёх, а скрипту или серверу, которые их сравнивают, для этого нужно всего несколько строк кода.

Распространённые конфигурации разделяет очень много браузеров, а необычные очень мало. Типичное для ноутбука число ядер, обычная строка платформы и широко распространённый список языков сами по себе говорят немного. Число ядер, далёкое от того, что обычно сообщают потребительские устройства, редкий уровень памяти или необычный список языков сужают группу браузеров, которые могли бы дать такую запись. Точный эффект зависит от аудитории сайта, который её собирает, поэтому единой цифры здесь не приводится.

Почему одно изменённое значение создаёт несоответствие

Практический вывод состоит в том, что значения navigator не независимы. Они описывают одну машину, и сайт может проверить, что они описывают именно её. Когда меняется только одно значение, остальные продолжают описывать исходную машину, и разница между ними сама становится сигналом.

Изменённая строка User-Agent

Подмена строки User-Agent это самый старый подход. Допустим, расширение заменяет navigator.userAgent на строку macOS, а navigator.platform по-прежнему возвращает "Win32". Теперь два значения называют разные операционные системы. Та же проблема возникает, когда navigator.userAgentData по-прежнему сообщает исходную платформу или когда заголовки Client Hints формируются по другим настройкам, чем значения JavaScript.

Сайту не нужно знать, какое из значений правдиво. Ему достаточно увидеть, что они противоречат друг другу, а противоречие отличает браузер сильнее, чем любое из значений в отдельности.

Случайные значения

У рандомизации похожая слабость. Если для каждой сессии случайно выбирать число ядер и значение памяти, получаются сочетания, которых почти нет у реальных устройств: например, строка мобильной платформы рядом с числом ядер, характерным для настольного компьютера, или значение памяти, не вяжущееся с остальным заявленным оборудованием.

Значение, которое меняется при каждом визите, не проходит и простейшую проверку на стабильность, потому что настоящий браузер при следующем визите сообщает те же числа оборудования. Значения, одновременно необычные и нестабильные, отличают браузер сильнее, чем настоящие значения, которые они заменили.

Изменения, сделанные не в том месте

Место изменения важно не меньше, чем само изменение. Скрипт, внедрённый в страницу, может повлиять только на то, что читает основной поток. У Web Worker есть собственная глобальная область и собственный navigator, поэтому изменение на уровне страницы, не доходящее до воркеров, оставляет там исходные значения видимыми. Заголовки запросов формирует сетевой код браузера, а не скрипт страницы, поэтому изменение на уровне страницы никогда их не затрагивает. В результате получаются три ответа там, где должен быть один.

Другие распространённые меры этот сигнал тоже не затрагивают. VPN меняет сетевой адрес и оставляет значения navigator прежними. Приватный режим сохраняет те же значения оборудования и языка. Очистка cookie удаляет сохранённое состояние, но не меняет того, что браузер сообщает о себе.

Короткий набор правил описывает, что означает согласованность на практике:

  • Операционная система в строке User-Agent совпадает с navigator.platform и с платформой в navigator.userAgentData.
  • Бренд и основная версия браузера совпадают в строке User-Agent, в списке брендов userAgentData и в заголовке Sec-CH-UA.
  • Число ядер и уровень памяти правдоподобны для класса устройств, который подразумевает платформа.
  • navigator.languages правдоподобен для указанной локали и совпадает с заголовком Accept-Language.
  • Каждое из этих значений одинаково в основном потоке, в воркерах и в повторных сессиях.

Проверка согласованности между потоками и заголовками

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

Основной поток и Web Worker

Откройте страницу, которую вы контролируете, и прочитайте значения в основном потоке: строку User-Agent, платформу, производителя, число логических процессоров, память устройства, список языков, а также список брендов и платформу из navigator.userAgentData. Запишите их. Затем запустите из той же страницы выделенный Web Worker, пусть он прочитает те же свойства из собственного navigator и передаст результат обратно на страницу.

Сравните две записи поле за полем. Они должны быть одинаковыми. Различие обычно означает, что значение было задано скриптом страницы либо что воркер читает его из другого источника, чем страница. Выделенный воркер проще всего проверить, а общие и сервисные воркеры можно добавить в то же сравнение.

Заголовки Client Hints

Затем сравните результат getHighEntropyValues() с тем, что получает сервер. Метод возвращает промис со значениями, которые вы перечислили, например с версией платформы, архитектурой, разрядностью и полным списком версий. На стороне сервера заголовки с более высокой энтропией приходят только после того, как предыдущий ответ содержал заголовок Accept-CH, который их запрашивает. Поэтому для тестовой страницы нужен сервер под вашим контролем, который отправляет Accept-CH и записывает получаемые заголовки запросов.

Сравните список брендов и платформу в Sec-CH-UA и Sec-CH-UA-Platform с объектом userAgentData, а заголовки версии платформы и архитектуры сравните с результатом высокой энтропии. Все они должны описывать тот же браузер и ту же платформу, что и строка User-Agent.

Повторные сессии

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

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

Полный список проверок по порядку:

  1. Запишите значения navigator в основном потоке.
  2. Запишите те же значения внутри Web Worker и сравните их поле за полем.
  3. Запросите значения высокой энтропии и сравните их со списком брендов и платформой из userAgentData.
  4. Перехватите заголовки Client Hints на сервере под вашим контролем и сравните их со значениями JavaScript.
  5. Повторите всё в новой сессии с тем же профилем и сравните записи.
  6. Меняйте по одной настройке за раз и повторяйте сравнение после каждого изменения.

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

Запуск с профилем

В BotBrowser значения navigator берутся из загруженного профиля, поэтому самый простой запуск состоит из профиля и временного каталога пользовательских данных:

chrome --bot-profile="path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

Документация BotBrowser описывает профиль как источник значений идентичности, оборудования, локали, сети и мультимедийных устройств и указывает, что значения JavaScript, HTTP-заголовки и контексты Worker возвращают из него согласованные значения. Начните с этой базы и выполните описанные выше проверки, прежде чем добавлять любые другие параметры. Без профиля значения navigator отражают ту машину, на которой вы действительно работаете.

Язык и локаль можно задать явно с помощью --bot-languages и --bot-locale. Для сетевой информации --bot-network-info-override управляет значениями navigator.connection и соответствующими заголовками Client Hints, а документация ограничивает получающуюся политику рамками BrowserContext. Задайте его до создания первой страницы в этом контексте, чтобы все страницы и воркеры контекста видели одни и те же значения.

chrome --bot-profile="path/to/profile.enc" \
       --bot-languages="en-US,en" \
       --bot-locale="en-US" \
       --bot-network-info-override \
       --user-data-dir="$(mktemp -d)"

Лучше выбрать другой профиль, чем переопределять отдельные значения поверх имеющегося. Профиль построен так, чтобы связанные значения совпадали, а изменение одного из них, например числа ядер, оставляет без изменений значения, которые от него зависят. Пользовательское управление User-Agent, параметры языка и локали и некоторые параметры идентичности, такие как бренд и версия браузера, в документации ограничены уровнем лицензии, поэтому прежде чем на них рассчитывать, уточните, что входит в вашу лицензию.

Что BotBrowser контролирует, а что нет

BotBrowser получает значения navigator (userAgent, platform, hardwareConcurrency, deviceMemory, languages и userAgentData) из загруженного профиля, поэтому основной поток, воркеры и заголовки Client Hints возвращают один согласованный набор, а параметр --bot-network-info-override управляет значениями navigator.connection и соответствующими Client Hints, что даёт вам воспроизводимую конфигурацию для выполнения проверок согласованности выше. BotBrowser не может помешать сайтам собирать значения navigator и сопоставлять их с другими сигналами, не может гарантировать, что профиль совпадает с реальным оборудованием или ожиданиями сайта, и не заменяет согласованность сети, аккаунта или поведения; пользовательское управление User-Agent зависит от уровня лицензии.

Эти ограничения стоит расписать, потому что согласованный набор значений navigator отвечает лишь на один из вопросов, которые может задать сайт.

  • Сайт по-прежнему может читать значения navigator и объединять их с сигналами canvas, WebGL, шрифтов и экрана. Каждая из этих поверхностей требует отдельной проверки.
  • Профиль описывает устройство, но не является этим устройством. У сайта могут быть ожидания относительно оборудования или программ, о которых ни один профиль не может знать заранее.
  • Сетевое расположение, история аккаунта, репутация и поведение являются отдельными входными данными. Согласованные значения navigator ни одно из них не меняют.
  • Описанное в документации поведение относится к корректному профилю, загруженному в поддерживаемой конфигурации, поэтому проверяйте его в своей конфигурации по списку проверок выше.

Относитесь к согласованности navigator как к одной части цельной конфигурации. Список проверок говорит, выполняется ли эта часть, и ничего не говорит о том, как конкретный сайт отнесётся к сессии.

Вопросы о значениях navigator

В: Достаточно ли hardwareConcurrency, чтобы идентифицировать человека? О: Нет. Это один вход из многих. Распространённые значения разделяют многие браузеры, а редкие сужают группу сильнее, но полезный сигнал возникает из сочетания с платформой, памятью, языком и другими поверхностями.

В: Почему deviceMemory останавливается на 8? О: Значение приближённое, и браузеры на основе Chromium ограничивают его, чтобы снизить точность описания машины. Другие семейства браузеров это свойство не предоставляют вовсе, поэтому там его отсутствие нормально.

В: Помогает ли изменение только строки User-Agent? О: Нет, если navigator.platform, navigator.userAgentData или заголовки Client Hints всё ещё описывают исходный браузер. Связанные значения должны меняться вместе.

В: Меняют ли VPN или приватный режим значения navigator? О: Нет. Значения берутся из браузера и операционной системы, а не из сетевого маршрута или режима просмотра.

В: Зачем сравнивать Web Worker с основным потоком? О: У воркера есть собственный navigator. Значение, изменённое только в скрипте страницы, остаётся там прежним, поэтому воркер это самое быстрое место, чтобы найти пробел.

В: Делает ли BotBrowser профиль равным реальному оборудованию? О: Нет. Профиль определяет значения, которые сообщает браузер, и поддерживает их согласованность между контекстами. Он не превращает машину в устройство, которое описывает профиль.

Связанные темы: Client Hints, число ядер процессора, часовой пояс, локаль и язык и сетевая информация. Полный набор средств управления описан на странице возможностей, а согласованность navigator можно проверить самостоятельно в Центре проверки.

Практический итог

Начинайте с профиля, а не со списка переопределений. Загрузите один профиль, прочитайте семь значений, которые несут основную часть сигнала (navigator.userAgent, navigator.platform, navigator.vendor, navigator.hardwareConcurrency, navigator.deviceMemory, navigator.languages, navigator.userAgentData), и запишите, что вернуло каждое.

  1. Сравните эту запись с тем же чтением внутри new Worker('worker.js'); расхождение указывает на значение, заданное скриптом страницы.
  2. Сравните userAgentData.brands и платформу с заголовками Sec-CH-UA и Sec-CH-UA-Platform, которые получает ваш сервер после отправки Accept-CH.
  3. Повторите чтение в новой сессии с тем же профилем; значения платформы и оборудования не должны меняться между сессиями.
  4. Если два представления расходятся, замените профиль, а не значение, потому что второе переопределение добавляет второе место, где возможен разрыв.

Набор, прошедший эти четыре шага, согласован, и согласованность это всё, что утверждает данная поверхность: браузер одинаково отвечает на один вопрос везде, что пока ничего не говорит о том, как сайт обойдётся с сессией.

Источники

Публичные материалы, использованные для утверждений о navigator, Client Hints и BotBrowser в этой статье:

#Navigator#fingerprinting#идентичность браузера#приватность

Эта статья входит в руководство: Что такое отпечаток браузера?

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

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