Смена user-agent редко кого-то обманывает. Узнайте, как сайты выявляют подмену через порядок заголовков, client hints, проверки движка и отпечаток.
Подмена user-agent — это изменение строки user-agent, которую отправляет ваш браузер, чтобы веб-сайт думал, будто вы используете другой браузер, устройство или операционную систему. Сделать это легко — достаточно одной настройки или расширения, — но против сайта, который действительно присматривается, это редко срабатывает, потому что user-agent — лишь один из десятков сигналов, что излучает ваш браузер, а остальные тихо противоречат лжи. Это руководство объясняет, как обнаруживают подмену: согласованность заголовков, client hints, проверки движка JavaScript и несоответствия отпечатка.
Ключевые выводы
- Строка user-agent — это самостоятельно сообщаемое, свободно редактируемое заявление: сам по себе сервер не может ничего по нему проверить, поэтому современное обнаружение трактует его как непроверенное утверждение, которое нужно сверять.
- Браузер выдаёт десятки других сигналов (порядок HTTP-заголовков, заголовки
sec-*, User-Agent Client Hints, поведение движка JavaScript, canvas/WebGL/экран/касания), и все они должны согласовываться с заявленной личностью. - Подмена терпит неудачу потому, что подделать одну строку текста тривиально, а подделать всё наблюдаемое поведение браузера согласованно — очень трудно.
- Обнаружение вероятностно: каждое противоречие повышает оценку подозрительности, а не выносит однозначный вердикт «да/нет».
- Поведение на уровне движка и согласованность HTTP-заголовков — среди самых трудных для подделки сигналов, ведь они требуют воспроизведения полной реализации настоящего браузера.
Что такое подмена user-agent?
Каждый запрос, который делает ваш браузер, включает строку user-agent — строку текста вида Mozilla/5.0 ... Chrome/120.0 ..., объявляющую браузер, версию и платформу. Подмена означает намеренное изменение этой строки. Люди делают это по многим причинам: ради приватности (слиться с толпой или сломать отслеживание), доступа к контенту, ограниченному определёнными браузерами, веб-скрапинга, автоматизированного тестирования или — на злонамеренном конце — ради мошенничества и ботового трафика, замаскированного под реальных пользователей.
Изменить саму строку тривиально. Проблема в том, что user-agent — это заявление, а браузер выдаёт десятки других фактов о себе, которые сервер может сверить с этим заявлением. Когда они не сходятся, подмена раскрывается.
Почему одной строке user-agent нельзя доверять
Сервер, который читает только user-agent, верит браузеру на слово о том, чем тот является. Но user-agent сообщается самим браузером и свободно редактируется, поэтому сам по себе он ничего не доказывает. Современное обнаружение трактует его как непроверенное утверждение и затем спрашивает: действительно ли всё остальное, что делает этот браузер, соответствует реальному экземпляру того, чем он себя называет? Обычно — нет, потому что подделать строку легко, тогда как подделать всё наблюдаемое поведение браузера очень трудно.
Как сайты обнаруживают подменённый user-agent
Обнаружение работает за счёт сбора независимых сигналов и проверки их на внутреннюю согласованность. Основные техники:
Согласованность HTTP-заголовков (порядок и заголовки sec-*)
Разные браузеры отправляют разные HTTP-заголовки, в разном порядке, с разными значениями. Chrome отправляет набор заголовков sec-ch-ua и sec-fetch-*, которых нет у Firefox; позиция заголовка User-Agent внутри запроса различается у браузеров; а значения Accept, Accept-Language и Accept-Encoding следуют специфичным для браузера закономерностям. Если запрос заявляет, что это Chrome, но в нём отсутствуют заголовки sec-* от Chrome — или его заголовки упорядочены как у Firefox, — заявление вызывает подозрение. Ничего из этого не видно в самой строке user-agent, и большинство инструментов подмены не утруждают себя воспроизведением этого.
Несоответствие Client Hints и user-agent
Браузеры на Chromium предоставляют User-Agent Client Hints — структурированный, читаемый из JavaScript источник той же информации о браузере и платформе, доступный через API navigator.userAgentData. Сервер может запросить высокоэнтропийные client hints и сравнить их со строкой user-agent. Если user-agent говорит «Safari на macOS», но API client-hints существует и сообщает о Chromium на Windows, эти двое расходятся, и подмена очевидна — ведь настоящий Safari вообще не предоставлял бы Chromium-овские client hints.
Проверки движка JavaScript и функций
Каждый движок реализует JavaScript и веб-платформу немного по-своему, и эти различия наблюдаемы в коде. Детектор может проверить, присутствуют ли API, которые должны существовать для заявленного браузера, протестировать специфичные для движка особенности или запустить микробенчмарки, чьё время выполнения служит отпечатком движка JavaScript. «Firefox», который предоставляет API только для Chrome или чьё поведение движка совпадает с V8, а не со SpiderMonkey, — подменён. Это напрямую связано с тем, какой движок рендеринга браузер использует на самом деле, — движок куда труднее подделать, чем название.
Несоответствие отпечатка (canvas, WebGL, экран, касания)
Наконец, само устройство выдаёт сигналы, которые должны согласовываться с заявленным браузером и платформой:
- Canvas и WebGL отрисовываются по-разному в зависимости от GPU, драйвера и ОС; мобильный user-agent, подкреплённый сигнатурой десктопного GPU, — это тревожный признак. О том, как это работает, см. обнаружение Canvas-отпечатка.
- Размеры экрана, которые больше видимого окна или не соответствуют заявленному классу устройства, подозрительны.
- Поддержка касаний: телефонный user-agent на устройстве, которое не сообщает о событиях касания, редко имеет смысл.
Каждый сигнал по отдельности слаб, но вместе они образуют профиль, которому user-agent обязан соответствовать, — и простая смена строки за ним не угонится.
Как серверные и клиентские сигналы противоречат подменённому UA
Подмена разваливается потому, что ей приходится обмануть сразу двух очень разных наблюдателей: сервер, читающий сырой HTTP, и JavaScript, исполняемый внутри страницы. Инструмент подмены, который латает одного, обычно забывает про другого, и их версии перестают совпадать.
На стороне сервера, ещё до того как запустится хоть один скрипт, сам запрос уже несёт улики. Набор и порядок заголовков HTTP/2, наличие специфичных для Chromium заголовков sec-ch-ua и TLS ClientHello наблюдаются прежде, чем будет разобран хоть один байт страницы. В частности, TLS-рукопожатие порождает устойчивую сигнатуру — обычно сводимую к хешу JA3 или JA4 — выводимую из наборов шифров и расширений, которые предлагает клиент. Эта сигнатура отражает нижележащий сетевой стек (BoringSSL в Chromium, NSS в Firefox), а не строку user-agent, поэтому запрос, заявляющий о себе как Firefox, но предъявляющий TLS-отпечаток Chromium, противоречив по своей сути. Ничего из этого нельзя изменить, отредактировав user-agent в настройках браузера.
На стороне клиента JavaScript может опрашивать среду исполнения напрямую. navigator.userAgentData либо существует (Chromium), либо нет (Firefox, Safari) — и подменённая строка не способна вызвать этот API к жизни. Помимо этого, наличие или отсутствие специфичных для движка глобальных объектов и API, точный способ сериализации чисел и дат, формулировки сообщений об ошибках и временной профиль плотных циклов — всё это выдаёт, какой движок JavaScript исполняется на самом деле. Даже CSS выдаёт движок: свойства с вендорными префиксами, отрисовка элементов форм по умолчанию и флаги поддержки, запрашиваемые через CSS.supports(), различаются между Blink, Gecko и WebKit. Детектор просто проверяет, согласуются ли эти клиентские факты с тем, что заявляют заголовки и user-agent.
Заявлено и на самом деле: несколько показательных примеров
| Заявленная личность | Настоящий экземпляр показал бы | Что часто показывает грубая подмена |
|---|---|---|
| Safari на macOS | Нет заголовков sec-ch-ua; navigator.userAgentData undefined; CSS-улики WebKit | Заголовки sec-ch-ua от Chromium и определённый userAgentData |
| Firefox на Windows | Порядок заголовков Gecko; тайминги SpiderMonkey; нет Chromium client hints | Поведение движка в стиле V8 и TLS/JA3-сигнатура Chromium |
| iPhone Safari (мобильный) | Есть события касания; мобильный GPU в WebGL; маленький экран | Строка десктопного GPU-рендерера и отсутствие касаний |
| Chrome на Android | sec-ch-ua-mobile: ?1; строки ARM-GPU | sec-ch-ua-mobile: ?0 или строка десктопного GPU NVIDIA/Intel |
Каждая строка — это противоречие, которое детектор может пометить, ни разу не «доказывая» ложность user-agent: ему достаточно заметить, что два независимых сигнала не могут быть истинны одновременно.
Как проверить это самому
Серверная ферма для этого не нужна. Откройте консоль DevTools в браузере и выполните navigator.userAgent и navigator.userAgentData рядом: в Chromium второе вернёт объект, в Firefox и Safari — undefined, какую бы строку вы ни подменили. С помощью панели сети осмотрите фактические заголовки запроса, которые отправляет браузер, и убедитесь, присутствует ли sec-ch-ua. Затем смените user-agent расширением или эмуляцией устройства в DevTools и повторите — вы увидите, что строка изменилась, а client hints, поведение движка и строки GPU остались ровно теми же. Именно этот разрыв и измеряют системы обнаружения.
Проверьте собственный браузер на несоответствия
Многие из этих сигналов вы можете увидеть на самом себе. Запустите проверку ядра браузера от BrowserInsight, чтобы сравнить заявленный браузер с его реальным движком рендеринга, и инструмент обнаружения ботов, чтобы увидеть сигналы согласованности, которые взвесила бы автоматизированная система. Если вы используете инструменты приватности, изменяющие ваш user-agent, это также способ заметить, не вносят ли они новые несоответствия, делающие вас более узнаваемым, а не менее.
Часто задаваемые вопросы
Незаконно ли менять мой user-agent?
Нет. Изменение user-agent — это нормальное, законное действие, которое позволяют браузеры и расширения, и у него есть легитимные применения вроде тестирования и совместимости. Вопросы законности возникают лишь из того, что вы с этим делаете — мошенничество или несанкционированный доступ, — а не из самого факта изменения строки.
Может ли сайт обнаружить подмену со 100-процентной уверенностью?
Не всегда с уверенностью, но часто с высокой степенью вероятности. Обнаружение вероятностно: каждое несоответствие (отсутствующие заголовки, рассогласованные client hints, неправильное поведение движка, противоречивый отпечаток) повышает оценку подозрительности. Аккуратную подмену, которая держит все сигналы согласованными, поймать трудно, но обычные изменения user-agent оставляют множество следов.
Вызывают ли инструменты приватности и расширения против отпечатка ложные срабатывания?
Иногда. Инструменты, которые меняют user-agent или рандомизируют сигналы, могут создавать несоответствия, которые системы обнаружения трактуют как подмену, — это одна из причин, почему заботящиеся о приватности пользователи время от времени сталкиваются с дополнительными проверками на ботов. Хорошо спроектированные инструменты меняют сигналы согласованно, чтобы избежать этого; грубые делают вас заметнее.
Какой сигнал самый надёжный для обнаружения подмены?
Единственного такого нет — надёжность приходит от их сочетания. Тем не менее поведение на уровне движка и согласованность HTTP-заголовков — среди самых трудных для подделки, потому что они требуют воспроизведения полной реализации настоящего браузера, а не редактирования одной строки текста.
Заключение
Подмену user-agent легко попытаться сделать и трудно провернуть, потому что браузер раскрывает о себе куда больше, чем строка, которую он добровольно выдаёт. Порядок заголовков и заголовки sec-*, client hints, поведение движка JavaScript и отпечатки устройства — всё это должно согласовываться с заявлением, а правка в одну строку не удержит их в соответствии. Защищаете ли вы сайт или проверяете собственную настройку приватности — урок один и тот же: никогда не доверяйте одному только user-agent и проверяйте сигналы вокруг него.
Рекомендуем прочитать: