Как работают UA Client Hints: уровни с низкой и высокой энтропией, согласование Accept-CH и что это значит для отпечатка браузера.
Строка User-Agent существует с начала 1990-х годов — один-единственный заголовок, который сразу объявляет ваш браузер, версию, движок, операционную систему и класс устройства. За десятилетия он стал неуклюжим: он несёт в себе такие токены, как Mozilla/5.0, — отголоски давно исчезнувших браузеров, — и достаточно подробные сведения о платформе, чтобы служить пассивным сигналом для снятия отпечатка при каждом запросе. User-Agent Client Hints (UA-CH) — это структурированная замена Chromium. Вместо того чтобы транслировать всё заранее, API работает по двухуровневой модели раскрытия: небольшой набор подсказок с низкой энтропией отправляется при каждом запросе по умолчанию, а более богатый уровень с высокой энтропией выдаётся лишь тогда, когда сервер явно об этом просит.
Ключевые выводы
- Браузеры Chromium по умолчанию отправляют три подсказки с низкой энтропией (список брендов, флаг мобильного устройства, название платформы) при каждом HTTPS-запросе — без каких-либо действий со стороны сервера.
- Высокоэнтропийные детали (архитектура, полная версия, версия ОС, модель устройства) предоставляются только после того, как сервер сначала отправит заголовок ответа
Accept-CH. - Аналог на стороне JavaScript —
navigator.userAgentData— API, существующий только в Chromium; Firefox и Safari возвращаютundefined. - Chromium постепенно замораживает старую строку
User-Agentдо малоинформативного стаба, расширяя UA-CH как основной канал идентификации. - Для снятия отпечатка и обнаружения подмены само наличие
navigator.userAgentDataнадёжно идентифицирует Chromium, а высокоэнтропийные значения, если они предоставлены, раскрывают более конкретную идентичность браузера, чем когда-либо давала старая строка UA.
Почему устаревшая строка User-Agent нуждалась в замене
Изначальная строка UA создавалась для распознавания браузера: серверы читали её, определяли движок и отправляли подходящий контент. О приватности никто не думал. Типичная строка UA Chromium выглядит так:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Один этот заголовок пассивно раскрывает название и версию ОС, архитектуру процессора, класс платформы, бренд браузера и приблизительный номер версии — при каждом запросе, без каких-либо вопросов со стороны сервера. Вдобавок он превратился в ловушку совместимости: сайты начали ветвить логику по конкретным подстрокам, так что браузеры не могли изменить формат без риска сломать эти сайты. Это одновременно проблема обслуживания и проблема приватности. UA-CH решает обе: замораживает старую строку до стаба и предоставляет чистый версионированный API, через который серверы могут запрашивать ровно то, что им нужно.
Два уровня: подсказки с низкой и высокой энтропией
Модель UA-CH делит информацию о браузере на два уровня в зависимости от того, насколько они сужают идентификацию пользователя.
Подсказки с низкой энтропией (отправляются по умолчанию)
Chromium прикрепляет три заголовка Sec-CH-UA-* к каждому кросс-доменному HTTPS-запросу без каких-либо указаний со стороны сервера:
| Заголовок | Пример значения | Что раскрывает |
|---|---|---|
Sec-CH-UA | "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99" | Бренд(ы) браузера и основная версия |
Sec-CH-UA-Mobile | ?0 | Является ли устройство мобильным (?1) или нет (?0) |
Sec-CH-UA-Platform | "Windows" | Только обобщённое название ОС |
Они считаются низкоэнтропийными, потому что одни и те же значения разделяет огромная аудитория: знание того, что кто-то пользуется Chrome 124 на Windows, соответствует миллионам пользователей, а не единицам.
Подсказки с высокой энтропией (требуют Accept-CH)
Детали с более высоким разрешением — способные идентифицировать конкретную сборку устройства — по умолчанию отключены; сервер должен запросить их явно:
| Заголовок | Пример значения | Что раскрывает |
|---|---|---|
Sec-CH-UA-Arch | "x86" | Архитектура процессора |
Sec-CH-UA-Bitness | "64" | 32- или 64-битная платформа |
Sec-CH-UA-Full-Version-List | "Google Chrome";v="124.0.6367.60" | Полные строки версий для каждого бренда |
Sec-CH-UA-Model | "Pixel 7" | Модель устройства (преимущественно для мобильных) |
Sec-CH-UA-Platform-Version | "10.0.0" | Версия ОС |
Согласование Accept-CH
Протокол запроса высокоэнтропийных подсказок прост. При первом визите сервер отвечает заголовком Accept-CH, перечисляя нужные имена подсказок:
HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List, Sec-CH-UA-Arch, Sec-CH-UA-Platform-Version
При последующих запросах (и при перезагрузке страницы) браузер включает эти подсказки:
GET /page HTTP/1.1
Sec-CH-UA: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
Sec-CH-UA-Full-Version-List: "Chromium";v="124.0.6367.60", "Google Chrome";v="124.0.6367.60", "Not-A.Brand";v="99.0.0.0"
Sec-CH-UA-Arch: "x86"
Sec-CH-UA-Platform-Version: "10.0.0"
Первая загрузка страницы намеренно информационно скудна: без предварительного opt-in сервер видит лишь три низкоэнтропийных значения по умолчанию.
JavaScript API: navigator.userAgentData
Те же данные доступны на клиентской стороне через navigator.userAgentData. API существует только в Chromium — Firefox и Safari возвращают undefined, — поэтому его наличие само по себе является надёжным сигналом идентификации движка.
Данные с низкой энтропией синхронны:
const uaData = navigator.userAgentData;
console.log(uaData.brands); // [{brand: "Chromium", version: "124"}, ...]
console.log(uaData.mobile); // false
console.log(uaData.platform); // "Windows"
Данные с высокой энтропией асинхронны и требуют явного запроса — зеркально отражая HTTP-модель Accept-CH:
navigator.userAgentData
.getHighEntropyValues(["architecture", "platformVersion", "fullVersionList"])
.then(ua => {
console.log(ua.architecture); // "x86"
console.log(ua.platformVersion); // "10.0.0"
console.log(ua.fullVersionList); // [{brand: "Google Chrome", version: "124.0.6367.60"}, ...]
});
Вызов getHighEntropyValues() не вызывает видимого пользователю запроса разрешения. Он даёт сайтам отслеживаемый, явный механизм получения детальных идентификационных данных, а не молчаливое чтение транслируемой строки. Кросс-доменные iframe могут быть заблокированы от высокоэнтропийных подсказок через Permissions-Policy.
UA-CH vs. устаревший User-Agent
| Свойство | Устаревший User-Agent | User-Agent Client Hints |
|---|---|---|
| Поддержка браузеров | Все браузеры | Только Chromium |
| Модель раскрытия | Всё транслируется пассивно | Низкая энтропия по умолчанию + высокая по запросу |
| Формат | Неструктурированная свободная строка | Структурированные пары ключ-значение |
| Возможность подмены | Тривиальна (одна строка) | Поле за полем; труднее сохранить согласованность |
| Намерение приватности | Никакого (исторический артефакт) | Прогрессивное раскрытие заложено в дизайне |
| Траектория | Постепенное замораживание до стаба | Расширяется; основной канал идентификации Chromium |
Chromium последовательно сокращает детализацию устаревшей строки UA. Начиная с Chrome 101 второстепенная версия ОС заморожена до 0.0.0, а второстепенная версия браузера в строке UA уменьшена. Траектория ведёт к стабу, передающему лишь «это браузер Chromium» — все детали переходят в UA-CH.
Последствия для снятия отпечатка
UA-CH меняет ландшафт снятия отпечатка сразу в двух направлениях.
Наличие navigator.userAgentData — надёжный детектор движка. Firefox и Safari не предоставляют этот API. Проверка navigator.userAgentData !== undefined мгновенно идентифицирует Chromium — надёжнее, чем парсинг строки UA, которую можно подменить одним расширением. Если поддельная UA утверждает, что это Firefox, но navigator.userAgentData существует и сообщает о брендах Chromium, противоречие очевидно. Это один из ключевых сигналов при обнаружении подмены user-agent.
Высокоэнтропийные подсказки могут быть конкретнее устаревшей строки UA. Замороженная строка UA больше не раскрывает полную второстепенную версию браузера; Sec-CH-UA-Full-Version-List — раскрывает. В сочетании с Sec-CH-UA-Arch и Sec-CH-UA-Platform-Version сервер, запросивший полный набор, получает более детальный отпечаток платформы, чем когда-либо давала пассивная трансляция, — но лишь с согласия браузера и только для серверов, явно запросивших это.
Замораживание строки UA ≠ улучшение приватности само по себе. Сокращение UA убирает один пассивный сигнал, но никак не влияет на множество других, из которых состоит отпечаток браузера: вывод рендеринга canvas, строки рендерера WebGL, параметры экрана, обработка аудио, установленные шрифты. UA-CH улучшает информационную гигиену на стороне сервера, не уменьшая общую площадь отпечатка.
UA-CH контролируется сервером, а не пользователем. Нет никакого интерфейса браузера, позволяющего пользователю отказать конкретному вызову getHighEntropyValues() от первопартийного JavaScript. Режим рандомизации отпечатка в Brave действительно перекрывает значения UA-CH; другие браузеры на базе Chromium — нет. Пользователям, желающим ограничить раскрытие, остаётся полагаться на антиотпечаточный режим браузера.
Проверьте сами
Откройте консоль DevTools и запустите navigator.userAgentData, чтобы увидеть низкоэнтропийные значения. Затем выполните:
navigator.userAgentData?.getHighEntropyValues(
["architecture", "model", "platformVersion", "fullVersionList"]
)
В Firefox и Safari API возвращает undefined. В Chromium он разрешается в объект с вашими реальными данными платформы. Инструмент проверки отпечатка BrowserInsight показывает ваши полные данные UA-CH наряду с остальными сигналами отпечатка, чтобы вы могли видеть, как все идентификационные сигналы комбинируются.
Часто задаваемые вопросы
Полностью ли UA-CH заменит строку User-Agent?
Пока нет, и уж точно не для браузеров, не основанных на Chromium. Firefox и Safari по-прежнему отправляют только традиционный заголовок User-Agent. Для Chromium UA-CH является предпочтительным каналом, а устаревшая UA замораживается, однако оба сосуществуют в текущих версиях. Сайтам, требующим широкой совместимости, по-прежнему приходится читать User-Agent как запасной вариант.
Можно ли подделать значения UA-CH?
Не через обычные настройки браузера. Эмуляция устройств в DevTools Chrome меняет строку UA, но не переопределяет navigator.userAgentData, — именно поэтому эмуляция устройств легко обнаруживается. Режим рандомизации отпечатка в Brave действительно подменяет значения UA-CH, но их согласованность между HTTP-заголовками и JavaScript API требует скоординированных изменений на уровне браузера.
Работает ли UA-CH по HTTP?
Нет. Согласование Accept-CH и заголовки Sec-CH-UA-* применяются только через HTTPS (и localhost). Обычные HTTP-соединения не отправляют заголовки UA-CH.
Поддерживает ли Firefox UA-CH?
Firefox не реализует UA-CH. Команда Mozilla выражала озабоченность тем, что при регулярных запросах высокоэнтропийных значений этот API может облегчить снятие отпечатка, а не затруднить его. Firefox продолжает использовать устаревший заголовок User-Agent.
Заключение
User-Agent Client Hints представляет собой продуманный архитектурный сдвиг: от единственной пассивной трансляции, раскрывающей детали платформы независимо от того, спрашивает ли кто-то об этом, к многоуровневой системе, где факты с низкой энтропией отправляются по умолчанию, а специфика с высокой энтропией требует явного запроса. Для разработчиков структурированный API проще разбирать и версионировать, чем произвольную строку UA. Для задач снятия отпечатка и обнаружения подмены он вводит чёткий сигнал разграничения Chromium и не-Chromium, одновременно предоставляя серверам, которым это нужно, более богатый и явный канал идентификации. Замораживание устаревшей строки UA устраняет один пассивный вектор; на смену ему приходит активное согласование между браузером и сервером.
Рекомендуем прочитать:


