BreakHub
СправочникОтпечаток браузера

Закат User-Agent и восход Client Hints

Строка User-Agent тянет за собой тридцать лет багажа совместимости, и Chrome заморозил ее до почти пустого шаблона. Подробности перешли в Client Hints. Что раскрывает каждый из них и как сайты ловят браузер с отредактированным UA.

6 мин чтения · Опубликовано 10 сентября 2026 г.

Откройте любой Chrome и выведите navigator.userAgent. Вы получите строку, которая противоречит сама себе: начинается с Mozilla/5.0, в середине упоминает AppleWebKit и «KHTML, like Gecko», а заканчивается Safari/537.36. Chrome, который выдает себя за родственника Netscape, Safari и Firefox одновременно. Это не ошибка. Это окаменелость, наросшая за десятилетия хаков ради совместимости, и понимание того, как она такой стала, почему ее теперь замораживают и чем сайты пользуются вместо нее, — тот фон, без которого не прочитать раздел о браузере в нашем отчете об отпечатке.

Строка, которой никто не верит

Исходная идея User-Agent была скромной: сказать серверу, какая программа спрашивает, чтобы он отдал что-то подходящее. Все пошло не так в девяностые, когда сайты начали пускать на свои «продвинутые» страницы только тех, у кого в UA есть «Mozilla». Internet Explorer немедленно назвался Mozilla, и каждый следующий браузер повторил трюк. Когда появился Chrome, он хотел, чтобы все сайты, проверяющие «Safari» или «Gecko», продолжали работать, — и напихал в строку все эти токены тоже. Итог — строка, где почти каждый токен лжет, а честны только хвостовой Chrome/1xx и кусок с платформой в скобках.

Хуже того, UA нес еще и версию ОС, архитектуру процессора, а на Android — точную модель устройства. Почти ни одному сайту это не нужно, но каждый трекер получает это бесплатно.

Сокращение UA в Chrome

Примерно в 2022–2023 годах Chrome поэтапно урезал строку UA. Сегодняшний UA Chrome выглядит примерно так: Windows всегда сообщает Windows NT 10.0; Win64; x64, будь у вас Windows 10 или 11; macOS зафиксирована на Intel Mac OS X 10_15_7 даже на Apple Silicon; Android заморожен на Android 10, а модель устройства заменена одной буквой K; от версии Chrome остался только мажорный номер, так что видно что-то вроде Chrome/128.0.0.0.

То есть UA Chrome сегодня сообщает три вещи и немногим больше: примерную платформу, мобильный ли это браузер и мажорную версию Chrome. В этом и был замысел: свести UA к низкой энтропии, а подробности перенести в механизм, который нужно запрашивать.

Client Hints: что отправляется по умолчанию, а что по запросу

Client Hints (UA-CH) — тот самый механизм, и он делит сведения о браузере на два уровня.

Три подсказки с низкой энтропией уходят с каждым запросом: Sec-CH-UA (бренды и мажорные версии, например "Chromium";v="128", "Google Chrome";v="128"), Sec-CH-UA-Mobile (?0 или ?1) и Sec-CH-UA-Platform ("Windows", "macOS", "Android" и так далее). Вместе они раскрывают примерно столько же, сколько сокращенный UA, — так и задумано.

Подсказки с высокой энтропией не отправляются без запроса: Sec-CH-UA-Platform-Version (различает Windows 10 и 11), Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Model (настоящая модель устройства), Sec-CH-UA-Full-Version-List (полные номера версий) и Sec-CH-UA-WoW64. Сервер получает их, ответив заголовком Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model, после чего браузер прикладывает их к последующим запросам. Скрипт страницы тоже может вызвать navigator.userAgentData.getHighEntropyValues(['platformVersion', 'model']) и получить их в Promise.

Одно недоразумение стоит прояснить сразу. «Требуется разрешение» не означает диалог, в котором вы что-то нажимаете. Это декларативный механизм: сайт заявляет, что хочет значения, и браузер выдает их, не спрашивая вас. Выигрыш в том, что по умолчанию их нет. В пассивном логе запросов ничего этого не содержится; кому нужно — должен попросить явно, а явный запрос можно проверять и ограничивать политикой. Заметьте также, что на момент написания ни Firefox, ни Safari не реализуют UA-CH, и ни один из них не заморозил UA так решительно, как Chrome. «Client Hints заменяют UA» — пока что история в основном про Chromium.

Странная запись «Not A(Brand»

Взгляните на Sec-CH-UA, и среди брендов найдется что-то похожее на мусор, например "Not A(Brand";v="99" или "Not/A)Brand";v="8". Это GREASE, намеренный шум. Мотивация практическая. Если разработчик напишет if (brands[0] === "Chromium"), любой новый бренд или перестановка сломает его сайт — ровно так, как десятилетия назад ломал сниффинг «Mozilla». Поэтому Chrome вставляет выдуманный бренд в случайную позицию с бессмысленной версией, вынуждая всех с первого дня писать терпимый к ошибкам парсер.

Определение движка: что заявляет UA, значит меньше, чем то, как браузер себя ведет

Изменить UA проще простого. Расширение, прокси или страница настроек в любом антидетект-браузере сделают это в один клик. Поэтому серьезные системы оценки рисков игнорируют то, что говорит UA, и смотрят на то, что делает браузер. Это и есть определение движка.

Типичны несколько семейств проверок:

  • window.chrome существует только в браузерах на Chromium. Старый Firefox выдавал InstallTrigger (в свежих версиях убран, так что эта проверка постепенно теряет силу). У Safari есть объекты, существующие только в WebKit, вроде ApplePayError и safari.pushNotification.
  • Поддержка CSS-возможностей. Истинное CSS.supports('-moz-appearance', 'none') почти всегда означает Gecko; свойства -webkit- есть и в Blink, и в WebKit, но точные наборы различаются.
  • Существует ли вообще navigator.userAgentData. Браузер, называющий себя Chrome 128 без этого объекта, — либо Firefox в UA от Chrome, либо объект вырезан расширением.
  • Формат стека ошибок. V8, SpiderMonkey и JavaScriptCore выдают заметно разный текст Error().stack, и никакая правка UA этого не меняет.

Когда движок известен, следующий шаг — оценить настоящую версию. Метод по сути тот же, что таблица Chrome Platform Status, только прочитанная задом наперед: каждый выпуск Chromium добавляет задокументированные API. В одном появился Array.prototype.toSorted, в другом — API планировщика, в третьем — новый CSS-селектор. Прощупывая эти возможности одну за другой, настоящую версию Chromium загоняют в узкий диапазон. Если UA заявляет Chrome 128, а API, вышедших в Chrome 115, нет — UA правили.

Наша страница User-Agent делает и кое-что попроще: кладет UA из заголовка HTTP-запроса рядом с navigator.userAgent из JavaScript. В норме они идентичны. Если различаются, объяснений по сути два: прокси переписывает заголовки по пути или расширение вмешивается на стороне JS. Это самый тяжелый штраф в нашей оценке подлинности, потому что ложных срабатываний у него почти нет.

Во что обходится несогласованность

Правка UA без правки движка имеет больше последствий, чем принято думать, и большинство из них — не в вашу пользу.

Системы оценки рисков считают расхождение «заявленный UA против измеренных возможностей» сильным признаком поддельного окружения, а это в лучшем случае больше CAPTCHA, в худшем — помеченный аккаунт. Логика совместимости уходит не в ту ветку: заявите более новую версию — сайт отдаст современный синтаксис, который ваш старый движок не разберет, и вы получите пустую страницу; заявите более старую — получите урезанный вариант. Есть и сторона безопасности. Напоминания об обновлении и функции безопасности, привязанные к версии, ориентируются на версию в UA, так что неверное значение тихо их отключает.

Коротко: правка UA — самая простая маскировка и самая простая для разоблачения. Либо делайте согласованным все окружение целиком, либо не трогайте ничего.

Вопросы и ответы

Client Hints хуже для приватности, чем UA? Подсказки с высокой энтропией действительно раскрывают больше, чем сокращенный UA, — например, настоящую версию Windows и модель устройства. Но раньше все это отдавалось в UA даром; теперь это по крайней мере нужно запросить, и отдают это только браузеры на Chromium. Сдвиг — от «видно всем» к «доступно по запросу». Это улучшение, но не принимайте его за функцию защиты приватности.

Firefox и Safari тоже заморозили свои UA? Не в той мере, что Chrome. Оба за годы убрали часть подробностей, но ни один не реализует UA-CH, так что их строки UA остаются главным идентификатором.

Может ли расширение для подмены UA убедить сайт, что я пользуюсь другим браузером? Только сайты, которые не читают ничего, кроме UA. Проверки возможностей видят насквозь, а когда вас поймали, «UA не соответствует движку» — сигнал хуже исходного UA. Если цель — меньше отслеживания, браузер с настройками по умолчанию, выглядящий как у всех, побеждает любую маскировку.