Закат 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. Если цель — меньше отслеживания, браузер с настройками по умолчанию, выглядящий как у всех, побеждает любую маскировку.