Как распознать headless-браузеры и автоматизацию на странице регистрации
Сигналы браузера, выдающие регистрации через Puppeteer, Playwright и Selenium, почему каждый можно подделать по отдельности и как их сочетать, не блокируя живых людей.
Почему боты теперь используют настоящие браузеры
Несколько лет назад большинство ботов регистрации были простыми HTTP-скриптами, которые отправляли вашу форму напрямую. Их легко остановить: они не выполняют JavaScript, так что ничего из того, что ваша страница вычисляет в браузере, не доходит. Сегодня большинство серьёзных ботов управляют настоящим браузером через Puppeteer, Playwright или Selenium — часто в headless-режиме, иногда через антидетект-браузер, маскирующий свой отпечаток. Они выполняют ваш JavaScript, отрисовывают страницу и заполняют форму так же, как человек.
Распознать их — значит найти места, где автоматизированный браузер отличается от браузера, которым пользуется человек. Ни один из сигналов ниже сам по себе не доказательство — настойчивый оператор может скрыть каждый, — но собирать их дёшево, и они складываются.
Сигнал 1: флаг WebDriver
Браузеры под автоматизацией типа WebDriver устанавливают navigator.webdriver в true. Это намеренная часть стандарта WebDriver, и стандартные настройки Selenium, Puppeteer и Playwright его выставляют.
const automated = navigator.webdriver === true;
«Stealth»-плагины удаляют или подменяют его, поэтому его отсутствие ничего не доказывает. А вот наличие почти однозначно: у настоящих пользователей его практически не бывает.
Сигнал 2: headless user agent
Headless Chrome называет себя HeadlessChrome в user agent, если оператор его не подменил. Проверяйте это и на сервере по заголовку запроса: строка, которую браузер сообщает в JavaScript, может отличаться от отправленной.
Сигнал 3: подключён клиент протокола DevTools
Puppeteer и Playwright управляют Chrome через протокол DevTools. Когда клиент протокола слушает события консоли, логирование объекта заставляет браузер его сериализовать — и при этом читать свойства, которых обычная страница никогда не касается. Известный способ это заметить — геттер, запоминающий, что его прочитали:
function devtoolsProtocolAttached() { let read = false; const e = new Error(); Object.defineProperty(e, "stack", { get() { read = true; return ""; } }); console.debug(e); return read; }
Он срабатывает и тогда, когда у разработчика открыты DevTools, поэтому давайте ему умеренный вес, а не считайте вердиктом.
Сигнал 4: программный рендеринг и странные окна
У headless-браузеров на серверах нет GPU, поэтому WebGL переходит на программный рендерер вроде SwiftShader или llvmpipe. Имя рендерера можно прочитать через расширение WEBGL_debug_renderer_info, если браузер его предоставляет. Некоторые headless-конфигурации также сообщают окно нулевой ширины или высоты. Те же признаки есть у виртуальных машин и удалённых рабочих столов, так что поодиночке это слабые сигналы.
Сигнал 5: противоречивый отпечаток
Антидетект-браузеры существуют, чтобы выглядеть как множество разных настоящих браузеров. Для этого они подменяют свойства, а подмены редко бывают полностью согласованными. Стоит сравнивать:
- Операционную систему в user agent с
navigator.platformи User-Agent Client Hints. - Семейство браузера в user agent с возможностями, которые есть только у этого движка.
- Установленные шрифты со шрифтами, которые поставляются с этой ОС.
- Canvas, нарисованный дважды подряд и давший две разные картинки, — признак внедрённого шума.
Notification.permissionсообщает «denied», а Permissions API — «prompt».
Каждое противоречие поодиночке слабое: расширения приватности и необычные конфигурации дают некоторые из них. Два-три вместе — уже сильная закономерность.
Сигнал 6: токен, который так и не вернулся
Простая и надёжная техника: пусть скрипт страницы регистрации запросит короткоживущий одноразовый токен, положит его в скрытое поле формы, а сервер его проверит. Бот, пропустивший ваш JavaScript, приходит без действительного токена; бот, повторно использующий старый, — с уже использованным. Не нужно знать, как устроен бот, чтобы увидеть, что вашу страницу он по-настоящему не выполнял. Делайте токен одноразовым, привязанным к вашему сайту и истекающим за минуты.
Сигнал 7: поведение, а не отпечаток
Отпечаток подделать можно, поведение — гораздо труднее. Человек читает форму, двигает указатель и печатает. Скрипт заполняет поля и отправляет их через несколько сотен миллисекунд после загрузки страницы, без единого доверенного события ввода.
Надёжное измерение не требует дополнительного ПО: агент выдаёт токен посетителя при загрузке страницы, а сервер сравнивает это время с моментом проверки. Меньше примерно секунды от загрузки до регистрации — это скрипт. Если агент ещё и сообщает доверенные события ввода, мгновенная отправка без событий указателя, клавиш и касаний становится вторым независимым подтверждением.
Оговорка к сигналу 3: в нынешнем Chrome трюк с DevTools срабатывает только когда клиент автоматизации подписан на события консоли, поэтому считайте его бонусом, а не основным детектором.
Комбинируйте, не блокируйте по одному сигналу
Считайте каждый сигнал баллами в общей оценке и решайте по сумме. Разумные начальные веса, от сильного к слабому:
| Сигнал | Вес | Почему |
|---|---|---|
navigator.webdriver равен true | высокий | У настоящих пользователей почти никогда не бывает true |
| User agent HeadlessChrome | высокий | Его отправляют только headless-сборки |
| Токен отсутствует или повторный | высокий | Скрипт страницы не выполнился или выполнился один раз на много регистраций |
| Подключён протокол DevTools | средний | Срабатывает и у разработчиков с открытыми DevTools |
| Противоречия ОС или браузера | средний | Подмены антидетекта, но и некоторые расширения |
| Программный рендерер, нулевое окно | низкий | Есть у ВМ и удалённых рабочих столов |
Сочетайте сигналы браузера с серверными — регистрации из облачных диапазонов IP, всплески из одной подсети, аккаунты на одном устройстве, — и очень немногие боты будут выглядеть чистыми по всем сразу.
Чего делать не стоит
- Не блокируйте только из-за отсутствия плагинов или языков. Браузеры, усиленные для приватности, их убирают.
- Не отдавайте логику обнаружения в виде проверок с очевидными названиями, которые оператор может найти и обойти разом; собирайте в браузере сырые данные и решайте на сервере.
- Не доверяйте слепо тому, что сообщает браузер. Клиент под контролем бота. Проверка происходит на вашем сервере, с вашим секретом.
Как это делает Attrelix
Агент Attrelix собирает эти данные браузера и одноразовый токен посетителя на вашей странице регистрации; сервер объединяет их с сигналами сети, почтового ящика и связанных аккаунтов в одну оценку. Все веса открыто опубликованы в документации, и ни один слабый сигнал сам по себе не отправит регистрацию на проверку.
Итог
- Современные боты используют настоящие браузеры; ищите, чем автоматизация отличается от человека.
- WebDriver, headless user agent и отсутствие токена — сильные сигналы; остальные слабые, но складываются.
- Решайте на сервере по сумме баллов, а не по одному флагу браузера.