AntiDetect
Возможности Технология Цены Для кого
Документация Блог FAQ
Язык
EnglishItalianoDeutschEspañolРусский
Скачать

User Agent переехал, а половина подмены осталась на месте

Chrome заморозил строку user agent и перенёс настоящие сведения в Client Hints. Многие сборки по-прежнему переписывают старую строку, а navigator.userAgentData продолжает говорить правду — противоречие, доступное любой странице ценой одного await.

Почему user agent заморозили

Строка user agent превратилась в палеонтологическую летопись. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36 утверждает, что это Mozilla, Safari и KHTML, — ничего из этого не верно, и всё ради совместимости, тянущейся из девяностых.

Кроме того, это была поверхность пассивного фингерпринтинга: каждый запрос сообщал версию ОС, архитектуру процессора и точную сборку браузера всем сторонним скриптам на странице — нужно это кому-то или нет.

Ответом Google стали User-Agent Client Hints. Старая строка ещё существует, но постепенно замораживается: обратите внимание, что Windows NT 10.0 теперь сообщает и Windows 11, а поля младшей версии закреплены как 0.0.0. Настоящие подробности переехали на новую поверхность, разделённую на два уровня по степени опознаваемости.

Низкая и высокая энтропия

Подсказки с низкой энтропией отправляются с каждым запросом без всякого запроса, потому что раскрывают немного:

Подсказки с высокой энтропией придерживаются, пока сервер не запросит их заголовком ответа Accept-CH или пока их не попросит скрипт:

Это разграничение задумывалось как средство защиты приватности. На практике в контексте первой стороны Chrome отдаёт всё запрошенное без запроса подтверждения и без видимого сигнала, так что скрипту фингерпринтинга достаточно вызвать getHighEntropyValues() со всеми именами полей — и он получит всё.

Где профили противоречат сами себе

Три ошибки встречаются постоянно, и все три выявляются одной строкой.

Строку поменяли, а объект — нет

Самая частая с большим отрывом. Инструмент переписывает navigator.userAgent, заявляя Chrome 147 на macOS, и оставляет navigator.userAgentData сообщать Chrome 131 под Windows. Проверка:

const ua = navigator.userAgent;
const d  = await navigator.userAgentData.getHighEntropyValues(
  ['platform','platformVersion','architecture','fullVersionList']);
// ua says "Macintosh; Intel Mac OS X 10_15_7"
// d.platform === "Windows"   →  contradiction, no ambiguity

Windows 10 или Windows 11

Поскольку строка UA сообщает Windows NT 10.0 для обеих, различить их можно только по platformVersion: значения ниже 13 означают Windows 10, 13 и выше — Windows 11. Профиль, который во всех витринных смыслах заявляет Windows 11, но возвращает platformVersion: "10.0.0", заявляет Windows 10 там, где это важно, — а следом у его набора шрифтов спросят про Segoe UI Variable.

Список брендов неверный

Запись GREASE — намеренно фальшивый бренд вроде "Not-A.Brand" — существует, чтобы серверы не зашивали список жёстко. Её точный текст и позиция меняются от версии Chrome к версии, а пунктуация со временем менялась: Not:A-Brand, Not.A/Brand, Not-A.Brand, с версией 8, 24 или 99 в зависимости от релиза. Список брендов, скопированный из старой сборки, — это несоответствие версий на самом виду рядом с более новым user agent.

Снова проблема worker

navigator.userAgentData существует внутри Web Worker и Service Worker. Эти контексты движок строит в собственных потоках, и, как разбиралось в статье про CDP, переопределение на уровне страницы до них не доходит.

// main thread: brands say 147
// worker: brands say whatever the binary really is
new Worker(URL.createObjectURL(new Blob([`
  navigator.userAgentData.getHighEntropyValues(['fullVersionList','platform'])
    .then(v => postMessage(v))
`], { type: 'text/javascript' })));

Любое расхождение здесь не просто подозрительно — оно окончательно. Не существует конфигурации браузера, в которой окно и worker законно сообщали бы разные списки брендов, потому что оба читают один источник.

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

Заголовки и JavaScript тоже должны совпадать

UA-CH существует сразу в двух местах — в HTTP-заголовках и в объекте JavaScript, — и создают их разные части браузера. Инструмент, который правит одно и не правит другое, создаёт противоречие, видимое в логе сервера вообще без клиентских скриптов.

Пары, которые обязаны совпадать:

ШапкаJavaScript
Sec-CH-UAuserAgentData.brands
Sec-CH-UA-PlatformuserAgentData.platform
Sec-CH-UA-MobileuserAgentData.mobile
Sec-CH-UA-Platform-VersionplatformVersion
Sec-CH-UA-Full-Version-ListfullVersionList
User-Agentnavigator.userAgent

Шесть пар, и последнюю все делают правильно. Полезная дисциплина — выводить их все из одной записи профиля, а не настраивать как отдельные поля; тот же довод, что в статье о согласованности, применённый к конкретной поверхности.

Шесть HTTP-заголовков Client Hints в паре со своими JavaScript-аналогами, одна пара нарушена
Шесть пар, созданных разными частями браузера. Поправьте одну сторону — и другая ей противоречит; это видно в логе сервера вообще без клиентских скриптов.

Как проверить профиль

Выполните это в профиле, который хотите проверить, и сверяйте каждую строку с user agent над ней:

(async () => {
  const d = await navigator.userAgentData.getHighEntropyValues(
    ['architecture','bitness','model','platformVersion','fullVersionList','wow64']);
  console.log(navigator.userAgent);
  console.log(navigator.userAgentData.platform, navigator.userAgentData.mobile);
  console.log(navigator.userAgentData.brands);
  console.log(d);
})();

Четыре вопроса к выводу:

  1. Совпадает ли платформа в объекте с платформой в строке?
  2. Совпадает ли старшая версия в fullVersionList с Chrome/NNN из строки?
  3. Согласуется ли platformVersion с ОС, которую вы собираетесь заявлять, — 13 или выше для Windows 11?
  4. Даёт ли worker те же ответы?

browserleaks.com/client-hints показывает сторону заголовков и сторону JavaScript вместе, так что шесть пар выше легко сравнить одним взглядом. Это самый быстрый способ найти наполовину применённую подмену.

Один номер версии — везде

P8 выводит строку UA, заголовки Client Hints и userAgentData из одного профиля — в том числе внутри worker, куда внедрённые скрипты не достают.

Начать бесплатно
Все статьи Далее: список шрифтов — признание вашей ОС