Как скрытые поля форм, ссылки-ловушки и проверки по времени ловят примитивных ботов, не мешая людям, и почему ложные срабатывания вызывает автозаполнение.
Honeypot — самая дешёвая проверка на бота, которую может запустить сайт: разместить на странице то, чего человек не увидит и не достанет, и считать любое взаимодействие с этим доказательством, что посетитель — программа. Это почти ничего не стоит сайту, не создаёт трения для живых людей и мгновенно выдаёт примитивного бота, который читает страницу как сырую разметку, а не как пиксели.
Ключевые выводы
- Вся хитрость в асимметрии. Человек взаимодействует с тем, что отрисовано; простой бот — с тем, что есть в DOM. Ловушка, существующая только в DOM, разделяет их.
- Три распространённых вида ловушек: скрытое поле формы, которое должно остаться пустым; скрытая ссылка на URL, запрещённый в
robots.txt; и проверка того, как быстро вернулась форма. - Настоящая инженерная сложность — не навредить людям с ограниченными возможностями. Экранные считыватели обходят DOM, так что ловушка, скрытая одним лишь CSS, может поймать человека, пользующегося вспомогательными технологиями.
- Автозаполнение — главная причина ложных срабатываний. Менеджеры паролей и автозаполнение браузера могут заполнить поле, которого пользователь не видел, поэтому заблокированный человек обычно ни в чём не виноват.
- Honeypot — первый фильтр, а не полная защита. Он ловит парсеры и спам-скрипты, но бессилен против настоящего браузера под управлением автоматизации.
Почему ловушка работает
Любая проверка на бота задаёт один вопрос: ведёт ли себя клиент как человек? Большинство ответов требуют анализа — например, согласованности отпечатка или поведенческой оценки. Honeypot обходится без анализа, заменяя вопрос на «трогал ли клиент то, чего человек трогать не мог?»
Человек видит отрисованную страницу, а спам-скрипт или парсер обычно читает HTML. Он находит каждый <input>, заполняет правдоподобными данными и отправляет. Если на странице есть поле, невидимое на экране, скрипт всё равно его заполнит, и сервер поймёт, что отправитель смотрел на страницу не так, как человек.
Honeypot в полях форм
Классическая ловушка — лишнее поле, которого зрячий пользователь никогда не увидит: вынесенное за пределы экрана, с нулевым размером или полностью прозрачное, но остающееся в DOM и — что принципиально — по-прежнему уходящее на сервер вместе с формой. (Поле с атрибутом disabled не отправилось бы вовсе, поэтому ловушку прячут, а не отключают.) Правило на сервере простое: если поле пришло непустым, отклонить отправку — тихо или с общей ошибкой.
От трёх деталей зависит, сработает ли ловушка:
type="hidden"— самый слабый вариант. Скрытое поле предназначено для хранения значения, и любой скрипт, обходящий форму, знает, что его надо не трогать или отправить без изменений. Ловушка должна выглядеть как поле, ожидающее ввода.- Имя имеет значение. Поле
email2илиwebsiteвыглядит как то, что скрипту следует заполнить, и как то, что должно заполнить автозаполнение. Нейтральное, не связанное по смыслу имя привлекает меньше случайных заполнений. - Проверять нужно на сервере. Ловушку, которую разбирает клиентский JavaScript, клиент может просто пропустить, а скрипты, ради которых honeypot и ставят, как раз никогда не выполняют JavaScript страницы.
Ограничение доступности
Именно здесь ошибается большинство honeypot-ловушек. Экранный считыватель читает не пиксели, а обходит DOM. Поле, просто вынесенное за экран, всё равно озвучивается, получает фокус по Tab и может запереть пользователя клавиатуры или вспомогательных технологий в поле, смысла которого он не понимает.
Разные CSS-приёмы ведут себя тут по-разному, и в этом вся проблема. display: none и visibility: hidden действительно убирают элемент из дерева доступности и из порядка табуляции — но именно их бот поприличнее проверяет в первую очередь, прежде чем заполнять поле. Поэтому на практике берут вынос за экран, нулевую прозрачность или нулевой размер, а такая ловушка остаётся и привлекательной для скрипта, и полностью открытой для вспомогательных технологий.
Значит, прятать приходится дважды: один раз от глаз, второй — от дерева доступности.
- Атрибут
inertна обёртке делает поддерево неинтерактивным, убирает его из порядка табуляции и скрывает от вспомогательных технологий. aria-hidden="true"иtabindex="-1"закрывают бо́льшую часть того же в старых окружениях безinert: вспомогательные технологии пропускают обёртку, а Tab — поле, хотя скрипт всё ещё может передать ему фокус.autocomplete="off"просит браузер не заполнять поле. Точную семантику смотрите в справке MDN по атрибутуautocomplete; браузеры считают его подсказкой, а не гарантией.
Вместе это выглядит примерно так:
<div inert aria-hidden="true" style="position:absolute;left:-9999px">
<label for="contact-ref">Leave this field blank</label>
<input type="text" id="contact-ref" name="contact-ref"
tabindex="-1" autocomplete="off">
</div>
Видимая подпись здесь не украшение. Это последний рубеж для того, кто всё-таки добрался до поля, — поэтому она должна говорить, что делать («оставьте это поле пустым»), а не объяснять, что перед вами ловушка.
Критерий — не «скрыто ли поле от глаз». Критерий такой: сможет ли человек с клавиатурой и экранным считывателем заполнить форму, ни разу не встретив ловушку.
Классическое ложное срабатывание: автозаполнение
Если вас заблокировали после обычной формы, скорее всего, дело в этом. Менеджеры паролей и автозаполнение подбирают поля по имени, метке и типу, и им безразлично, видно ли поле. Ловушка с именем phone или address2 может быть заполнена браузером в фоне, и сервер увидит «бота» в отправке живого человека.
То же происходит с расширениями, которые переписывают или подставляют значения в формы. Ничего из этого не вина человека. Хорошие реализации снижают риск, используя не связанные по смыслу имена полей и autocomplete="off", и считают заполненную ловушку одним сигналом из нескольких, а не поводом для автоматического бана.
Ловушки-ссылки и пути
Та же идея работает для краулеров. Сайт добавляет невидимую для людей ссылку, часто с rel="nofollow", на URL, запрещённый в его robots.txt. Клиент, запросивший этот URL, доказывает, что проигнорировал robots.txt.
Изящество в том, кого этот приём не ловит. Нужные вам поисковые системы, такие как Googlebot и Bingbot, соблюдают robots.txt, никогда не запрашивают запрещённый путь и потому не срабатывают. Попадаются именно те клиенты, которые и так не соблюдали правила сайта.
Полностью чистым приём всё же не назовёшь. Масса безобидных непоисковых клиентов — краулеры аудита сайтов, сканеры доступности, сканеры безопасности, архивные боты — идут по каждой найденной ссылке, и не все они сначала читают robots.txt. Сработавшая ловушка доказывает, что клиент проигнорировал правила, но не то, что он замышлял плохое. Отсюда и вывод: такой адрес разумнее ограничить по скорости или пометить, а не банить сразу.
Ловушки по времени
Третьему варианту скрытый элемент не нужен. Сервер при отрисовке формы выдаёт метку времени или подписанный токен и проверяет его при отправке. Форма, вернувшаяся за 300 миллисекунд, человеком не читалась. Но токен обязан быть подписанным или храниться на сервере: голая метка времени в скрытом поле — это просто число, которое клиент перепишет перед отправкой.
Но фиксированные пороги хрупки. Автозаполнение способно заполнить обычную форму почти мгновенно, постоянные пользователи точно знают, что вводить, а чуть более терпеливый бот просто подождёт. Время лучше всего работает как слабый сигнал поверх других и никогда — как единственная причина для отказа.
Место honeypot в общей защите
Honeypot — дешёвый первый фильтр. Он ловит примитивные скрипты, стоящие за большей частью спама в формах и наивного парсинга, до запуска любой дорогой проверки. Против настоящего браузера под управлением автоматизации он бессилен: тот отрисовывает страницу как человек, а скрипту можно велеть взаимодействовать только с видимым.
Поэтому он живёт рядом с остальной лестницей проверок из нашего руководства по методам обнаружения ботов: флаги автоматизации, утечки headless-браузеров, поведенческий анализ и системы проверки вроде страницы Cloudflare «Проверка браузера». Каждый уровень ловит то, что пропустил более дешёвый.
Если вас поймали
Заблокированный человек почти всегда споткнулся об автозаполнение или расширение, а не о настоящее обнаружение. Что стоит проверить в своём браузере:
- Повторите отправку с выключенными менеджером паролей и автозаполнением, вводя поля вручную.
- Отключите расширения, подставляющие или переписывающие значения форм, и повторите в чистом профиле.
- Проверьте, блокирует ли вас сайт и в других местах. Тогда дело скорее в сети или профиле браузера, а не в одной форме.
Чтобы увидеть, какие связанные с автоматизацией сигналы ваш браузер показывает сайтам, запустите нашу проверку на бота. Она лишь считывает то, что браузер и так сообщает, и всё выполняется локально.
Часто задаваемые вопросы
Что такое honeypot в веб-формах?
Поле ввода, которое человек не видит и не заполняет, но которое остаётся в разметке страницы. Если оно вернулось со значением, отправитель читал HTML, а не отрисованную страницу — это веское свидетельство автоматизации.
Останавливают ли honeypot-ловушки всех ботов?
Нет. Они ловят простые скрипты и парсеры. Настоящий браузер под управлением автоматизации отрисовывает страницу как человек и не тронет ловушку, невидимую на экране, поэтому honeypot — лишь один слой из нескольких.
Может ли honeypot заблокировать реальных пользователей?
Да, в основном из-за автозаполнения и менеджеров паролей, которые заполняют скрытые поля, а также из-за плохо сделанных ловушек, доступных вспомогательным технологиям. Аккуратные реализации используют inert, tabindex="-1" и autocomplete="off" и считают результат одним сигналом.
Почему краулеры поисковых систем не попадаются на ссылки-ловушки?
Потому что соблюдают robots.txt. Ссылка-ловушка ведёт на запрещённый путь, добросовестный краулер его не запрашивает, и попадаются только клиенты, игнорирующие правила.


