Как отличить ботов от людей: практическое руководство по классификации посетителей

На сервер приходят не посетители, а запросы. Человек может сделать один просмотр страницы и десяток запросов за ресурсами; поисковый робот может скачать тысячи страниц; ИИ-ассистент может скачать одну страницу, потому что человек задал ему вопрос. Полезный вопрос — не «это человек?», а «что это за клиент и что мне с ним делать?».

Журналы доступа — правильная отправная точка. Они полны в том смысле, в каком аналитика на JavaScript не полна: каждый запрос, дошедший до сервера, там есть, включая роботов, которые никогда не выполняют скрипт. Но при этом журналы скудны. Они записывают адрес, время, путь, статус, referer и заявленный user-agent. Намерение они не записывают.

Коротко. User-agent — это заявление. IP — это место. Cookie — это «может быть». Надёжная классификация получается из независимых признаков, которые согласуются между собой: проверенная сетевая личность, поведение запросов, непрерывность сессии и, там где он оправдывает свою цену, небольшой маячок на JavaScript со своего домена.

Это руководство начинается с того, что может доказать журнал доступа, а затем добавляет признаки, которые может собрать браузер. Оно держит в поле зрения три мысли: проверенный робот — не человек, headless-браузер умеет выполнять JavaScript, и «неизвестно» — допустимый ответ.

В примерах используются диапазоны адресов для документации (203.0.113.0/24, 198.51.100.0/24 и 192.0.2.0/24), так что ни один настоящий посетитель не раскрыт.

Что записывает журнал доступа

Начнём с одной строки из журнала Apache в формате combined:

203.0.113.42 - - [18/Jul/2026:14:22:07 +0300] "GET /catalog/pumps/ HTTP/1.1" 200 18432 "https://example.com/" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

Адрес из диапазона для документации. User-agent заявляет, что это Googlebot. Эта комбинация — вся проблема в одной строке.

Одна строка журнала, шесть полезных полей
Поле Пример Что оно говорит Где оно обманывает
Адрес клиента 203.0.113.42 Владелец сети (её ASN), страна, диапазон дата-центра или домашней сети NAT, VPN и прокси скрывают человека; CDN скрывает настоящего клиента
Отметка времени 18/Jul/2026:14:22:07 +0300 Ритм, часовой пояс, рабочие часы Намерение; робот может работать по человеческому графику
Строка запроса GET /catalog/pumps/ HTTP/1.1 Метод, путь и протокол Хотел ли человек эту страницу
Статус и байты 200 18432 Успех, ошибка, размер ответа Вовлечённость; 200 может быть страницей-заглушкой
Referer https://example.com/ Контекст перехода Правду; его часто нет или он подделан
User-Agent Mozilla/5.0 ... Заявленную личность клиента Настоящего клиента; любую строку может написать кто угодно

Две практические детали важнее, чем кажется. Во-первых, если сайт стоит за CDN или обратным прокси, записанный адрес — это прокси, а не посетитель. Записывайте переданный адрес клиента и непосредственного соседа, и доверяйте переданному заголовку только тогда, когда он пришёл от вашего собственного прокси. Во-вторых, стандартный формат combined не содержит длительности запроса, деталей TLS и большинства заголовков. Добавьте то, что действительно будете использовать, но не записывайте cookie, заголовки авторизации и полные строки запроса, в которых могут оказаться персональные данные.

На Debian или Ubuntu отдельный файл конфигурации Apache держит формат вне виртуального хоста:

/etc/apache2/conf-available/visitor-log.conf

sudo vi /etc/apache2/conf-available/visitor-log.conf

LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined_timing

Затем сослитесь на combined_timing в существующей директиве CustomLog. Включите фрагмент и перезагрузите Apache:

sudo a2enconf visitor-log

sudo systemctl reload apache2

%a — адрес клиента, а %D — время запроса в микросекундах. При прокси включите mod_remoteip и перечислите только те прокси, которыми управляете вы. Иначе злоумышленник подделает X-Forwarded-For и выберет личность, которую запишет ваш журнал. Доступные поля описаны в документации Apache: mod_log_config.

В nginx та же оговорка относится к $remote_addr: настройте real_ip со списком доверенных прокси и подумайте, не записывать ли непосредственного соседа и переданный адрес в отдельные поля.

То, чего журнал не видит, так же важно. Он не знает, выполнялся ли JavaScript, заполнял ли форму человек, прочитали ли страницу и вернётся ли посетитель завтра. Запрос к странице — не просмотр страницы. Поэтому классификация по журналу и классификация по браузеру дополняют друг друга, а не соревнуются.

Журнал всё же записывает то, что браузер обычно скачивает: CSS, JavaScript, картинки, шрифты и favicon. Их наличие или отсутствие — довод. Не доказательство. Держите это различие до конца руководства.

Проверка на реальных данных 2026 года

В июле 2026 года Валентина Меланина опубликовала трёхдневный аудит настоящего магазина оборудования для бизнеса: 16 705 запросов, 39 % из них автоматические, и каждая строка сверена с исходным IP. Проценты — полезная калибровка, а не всеобщий закон.

Заявленная личность против проверенной, три дня в июле 2026
Заявленный токен Запросов Подтверждено Что нашёл аудит
Googlebot 896 268 Около 70 % пришли не из сетей Google
Bytespider 1 073 0 Арендованные адреса AWS в Сингапуре, а не ByteDance
ChatGPT-User 265 237 71 IP, 23 сессии; живые запросы по инициативе пользователя
Bingbot 467 467 В этой выборке подтверждён полностью

Числа — не вся история. Два адреса Google Cloud заявили по пятнадцать разных личностей ботов, один адрес Cloudflare — одиннадцать. Один сервер — это не пятнадцать компаний, это сканер или проверяльщик доступа для ИИ, который меняет маски. 237 подтверждённых запросов ChatGPT-User пришли с 71 IP и образовали 23 сессии: люди задавали ChatGPT вопрос и вызывали живую загрузку. Веб-аналитика их не увидела. Отдельно 57 запросов ушли на служебные пути вроде /.git, /.ssh, /.env, /secrets.json и /actuator, все под именами ИИ-ботов. Это были сканеры в модной маске.

Метод аудита воспроизводим: сгруппировать по user-agent, выписать IP, сверить каждый IP с текущими диапазонами поставщика или с обратным и прямым подтверждением DNS, затем читать оставшиеся запросы как трафик роботов. Полный разбор — melanina.ru.

Важны два урока. Первый: известное имя — маска, а не личность. Второй: ИИ-трафик — не одно и то же. GPTBot — робот, который собирает данные для обучения. OAI-SearchBot — робот поискового индекса. ChatGPT-User — загрузка, вызванная вопросом человека. Последняя запущена человеком, но выполнена машиной: это не человеческий просмотр страницы и не обычный шум ботов. Схема классификации, в которой есть только «бот» и «человек», разметит его неверно.

Для более широкой базы: исследование 2026 года по более чем 4,6 млн запросов показало, что автоматический трафик — примерно половина всех веб-запросов. Точная доля зависит от сайта, недели и того, что вы считаете. Метод важнее заголовка.

Проверяйте имя, а не только user-agent

Фильтрация по известным именам — полезный первый проход. Она дешёвая, ловит честную автоматизацию и даёт словарь, с которым можно работать. Но это не проверка личности. Любой может отправить любую строку в User-Agent; руководство MDN по определению браузера по той же причине советует проверять возможности, а не разбирать UA.

Используйте две независимые проверки:

  1. Опубликованные диапазоны IP. Поставщик публикует JSON или блоки CIDR (диапазоны адресов) для своих роботов. Сверьте адрес из журнала с текущим списком.
  2. Обратное и прямое подтверждение DNS (FCrDNS). Сделайте обратный запрос адреса, проверьте, что имя хоста принадлежит домену поставщика, затем прямой запрос имени и проверьте, что он возвращает тот же адрес.

Одного обратного DNS мало. Кто управляет адресом, тот может поставить в его PTR-запись известное имя. Проверяемым заявление делают прямой запрос и проверка домена. Для Google имя хоста должно заканчиваться на googlebot.com, google.com или googleusercontent.com — в зависимости от типа робота.

host 66.249.66.1

1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.

host crawl-66-249-66-1.googlebot.com

crawl-66-249-66-1.googlebot.com has address 66.249.66.1

Первый запрос даёт имя; второй доказывает, что имя ведёт обратно. Поддельная PTR-запись пройдёт первую проверку, но не вторую, если только злоумышленник не управляет ещё и прямым DNS домена, которым не владеет, — поэтому проверка домена и важна.

Что поставщики опубликовали на октябрь 2026 года
Оператор Способ проверки Что проверять
Google Пять файлов IP по типам роботов + FCrDNS googlebot.com для обычных роботов; имена googleusercontent.com или google-proxy для загрузок по инициативе пользователя
Microsoft Bing Список IP + инструмент Verify Bingbot + FCrDNS Обратные имена заканчиваются на search.msn.com; список обновляйте каждый день
OpenAI Отдельный файл IP на каждого агента GPTBot, OAI-SearchBot, ChatGPT-User, OAI-AdsBot; опубликованного способа проверки rDNS нет
Anthropic Один общий файл IP Список не различает ClaudeBot, Claude-User и Claude-SearchBot
Perplexity Два файла IP PerplexityBot и Perplexity-User
Apple Список IP + FCrDNS Обратные имена заканчиваются на *.applebot.apple.com
Common Crawl Список IP + FCrDNS crawl.commoncrawl.org; обратный DNS для IPv6 не поддерживается
Amazon Три страницы с IP Amazonbot, Amzn-SearchBot, Amzn-User
Meta Опубликованного способа проверки нет На октябрь 2026 заявление meta-externalagent со страницы Meta проверить нельзя
Yandex FCrDNS Обратные имена заканчиваются на spider.yandex.com; используйте любой текущий список IP, который публикует поставщик

Списки меняются. Забирайте их у поставщика в тот день, когда используете; не копируйте блоки CIDR из статьи, в том числе из этой. Текущие инструкции и файлы Google — на странице Verify requests from Google; файлы и смысл отдельных агентов OpenAI — в её документации по роботам; Anthropic публикует один общий список; Perplexity описывает оба файла в своём руководстве по ботам.

Два имени в журнале не появятся никогда: Google-Extended и Applebot-Extended — это токены управления robots.txt, а не роботы. Если панель отчитывается о визитах от них, панель ошибается.

Проект ai.robots.txt — полезный словарь имён ИИ-роботов и готовая политика robots.txt. Используйте его, чтобы найти токены, а затем проверьте IP; сам список — не доказательство.

Программа Verified Bots Cloudflare и появляющиеся подписи Web Bot Auth — третий путь: провайдер на периметре или криптографическая подпись ручается за клиента. Они полезны, когда вы уже стоите за этим провайдером, но универсальными не являются.

Что на самом деле значит заявленное имя
Заявленный токен Что это Считать посетителем?
Googlebot, Bingbot, YandexBot Роботы поисковых систем Нет
GPTBot, ClaudeBot, CCBot, Bytespider Роботы, собирающие данные для обучения Нет
OAI-SearchBot, PerplexityBot Роботы поискового индекса ИИ Нет
ChatGPT-User, Perplexity-User, Claude-User Загрузка по инициативе пользователя Начато человеком, но это не просмотр страницы
curl, python-requests, Go-http-client, Scrapy, axios, HeadlessChrome Заявленная автоматизация Скорее всего нет, но проверьте
Мониторы доступности, предпросмотр ссылок, SEO-роботы Автоматические сервисы Нет

Проверенный робот — всё равно робот. Законность не делает его человеком. Держите verified_crawler отдельно от human в своей схеме, а unverified — отдельно от fake. Неудачная проверка значит «я не смог это подтвердить», а не «я доказал, что это мошенничество».

Поведение, которое оставляет след

Проверка личности ловит ботов, которые себя объявляют. Поведение ловит ботов, которые врут. Журнал даёт последовательность запросов, и эта последовательность часто информативнее любой отдельной строки.

Признаки, которые можно посчитать по обычному журналу доступа
Признак Как выглядит Сила
Доля ресурсов Бот: только HTML или одни и те же фиксированные ресурсы. Человек: CSS, JS, картинки и шрифты, неравномерно. Средняя
Ритм сессии Бот: ровные промежутки, мало разброса. Человек: всплески, паузы и возвраты. Средняя
Форма навигации Бот: порядок карты сайта, последовательные ID, глубокий обход. Человек: вход из поиска или соцсети, чтение, возвраты. Средняя
Методы HTTP Бот: HEAD, OPTIONS или TRACE; POST на HTML-страницы. Человек: GET и POST на настоящих формах. Высокая для сканеров
Пробы ошибок Бот: /.env, /.git, wp-login.php, /actuator. Человек: изредка битая ссылка. Высокая для сканеров
Несколько личностей с одного IP Бот: больше 3–5 user-agent с одного IP за короткое окно. Человек: обычно один или два. Высокая
Непрерывность cookie Бот: cookie нет или они случайны на каждом запросе. Человек: стабильная сессионная cookie между страницами. Средняя
Referer Бот: нет, указывает на себя или поддельный. Человек: поиск, соцсеть или внутренний переход. От низкой до средней
Распределение по времени Бот: ровное круглые сутки. Человек: местные рабочие часы. Сама по себе низкая
Тип сети Бот: облако или хостинг по ASN. Человек: домашняя или мобильная сеть, с оговоркой про VPN. Средняя
Favicon и robots.txt Бот: часто пропускает favicon, часто просит robots.txt. Человек: обычно наоборот. Низкая

Доля ресурсов и отрисовка

Браузер скачивает HTML, затем CSS, JavaScript, шрифты и картинки. Простой HTTP-клиент часто скачивает только HTML. Высокая доля HTML к ресурсам поэтому — слабый признак бота. Но Googlebot может скачивать ресурсы, когда отрисовывает страницу, а человек может их блокировать. Исследование 2026 года Shy Guys по 4,6 млн запросов обнаружило, что боты часто пропускают favicon; запрос favicon — слабый довод в пользу браузера, но не доказательство человека.

Считайте долю по сессии, а не по IP, когда можете: static_requests / html_requests. Сессия с 40 запросами HTML и без CSS, JavaScript и картинок — не читатель. Сессия с одним запросом HTML и без ресурсов может быть предзагрузкой или текстовым браузером.

Ритм

Боты часто ровные; люди — всплесками. Для каждой сессии возьмите промежутки между запросами и посчитайте коэффициент вариации: CV = stdev(gaps) / mean(gaps). CV около нуля на 20 и более запросах — машинный. CV больше 1 для людей обычен. Но вежливый робот со случайными задержками может выглядеть как человек, а панель с автообновлением — как ровный бот. Используйте ритм вместе с объёмом и формой путей, а не отдельно.

«Запросов в минуту» — плохой самостоятельный признак: робот может быть медленным, а человек может открыть тридцать вкладок. Рисунок промежутков информативнее среднего.

Форма навигации

Парсеры перечисляют. Они идут в порядке карты сайта, по последовательным ID товаров, по страницам категорий и ссылкам «следующая страница». Люди приходят из поиска или соцсети, читают, возвращаются, открывают новую вкладку и уходят. Сессия, которая начинается с глубокого URL и проходит двести страниц идеальной последовательностью, — не читатель.

Пробы ошибок — самая резкая версия этого признака. /.env, /.git, /wp-login.php и /actuator — не контент. Их скопление — подпись сканера, даже когда user-agent говорит «Chrome».

Две быстрые проверки, прежде чем писать парсер. В формате combined первое поле — адрес, девятое — статус:

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

Пример вывода:

1842 66.249.66.1 913 203.0.113.42 407 198.51.100.7

Счётчики — не классификация. Большое число может быть Googlebot за работой или парсером, притворяющимся Googlebot.

awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -nr | head -10

Пример вывода:

57 /.env 31 /.git/config 18 /wp-login.php 12 /actuator/env

Эти пути — подписи сканеров. Они дают высокую уверенность, даже когда остальной запрос выглядит как браузер.

Несколько личностей с одного IP

Сгруппируйте по IP и посчитайте разные строки user-agent за короткое окно. Больше трёх — подозрительно; аудит 2026 года нашёл два облачных IP, каждый из которых заявлял пятнадцать личностей. Общий корпоративный прокси, CDN или развёртывание обновления браузера может дать несколько законных user-agent, поэтому требуйте объёма и короткого окна. Это один из самых дешёвых ценных признаков в журнале.

Непрерывность cookie и сессии

Настоящий браузер обычно сохраняет сессионную cookie своего домена между страницами. Парсер часто выбрасывает cookie или получает новую сессию на каждом запросе. Но браузеры приватности, баннеры про cookie и API без состояния это ломают. Проверяйте, возвращается ли та же cookie по последовательности, а не есть ли cookie вообще.

Чтобы считать признаки по IP, а не прикидывать на глаз, сохраните этот скрипт как features.py. Он читает журнал combined, пропускает некорректные строки и печатает верхние адреса по числу запросов с долей ресурсов, долей ошибок и числом разных user-agent:

features.py

vi features.py

#!/usr/bin/env python3 """Print per-IP request, static, error, and user-agent counts.""" from __future__ import annotations import re import sys from collections import Counter, defaultdict LINE = re.compile( r'^(?P<ip>\S+) \S+ \S+ \[[^\]]+\] ' r'"(?P<method>\S+) (?P<path>\S+) [^"]+" ' r'(?P<status>\d{3}) \S+ "[^"]*" "(?P<agent>[^"]*)"' ) STATIC = (".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff2") def main(path: str) -> None: """Read a combined log and print the top IPs by request count.""" requests: Counter[str] = Counter() static: Counter[str] = Counter() errors: Counter[str] = Counter() agents: defaultdict[str, set[str]] = defaultdict(set) with open(path, encoding="utf-8", errors="replace") as log: for line in log: match = LINE.match(line) if not match: continue row = match.groupdict() ip = row["ip"] requests[ip] += 1 agents[ip].add(row["agent"]) if row["path"].lower().endswith(STATIC): static[ip] += 1 if row["status"].startswith(("4", "5")): errors[ip] += 1 for ip, count in requests.most_common(20): print( f"{ip:16} req={count:5d} " f"static={static[ip] / count:.2f} " f"errors={errors[ip] / count:.2f} " f"uas={len(agents[ip])}" ) if __name__ == "__main__": main(sys.argv[1] if len(sys.argv) > 1 else "access.log")

Запустите его на журнале:

python3 features.py access.log

Примерный вывод:

203.0.113.42 req= 913 static=0.04 errors=0.01 uas=1 66.249.66.1 req= 1842 static=0.02 errors=0.00 uas=1 198.51.100.7 req= 407 static=0.00 errors=0.38 uas=15

Один адрес — робот с большим объёмом и почти без ресурсов; у другого пятнадцать user-agent и 38 % ошибок. Скрипт ничего не решает. Он даёт признаки для шага оценки.

Что может добавить JavaScript

Журналы видят запрос; JavaScript видит клиента. В этом и обмен. JavaScript может наблюдать окружение и взаимодействие, но только у клиентов, которые его выполняют. Большинство роботов не выполняют; headless-браузер выполняет. Отсутствие маячка — сильный довод в пользу клиента без JavaScript. Наличие маячка — слабый довод в пользу человека.

Три слоя стоит собирать, именно в этом порядке:

  1. Существование и время. Выполнилась ли страница, когда, сколько и была ли она видима?
  2. Окружение и согласованность. Сходится ли самоописание браузера с заголовками запроса и с самим собой?
  3. Взаимодействие. Было ли событие указателя, прокрутки, клавиши или фокуса?

Начните с небольшого маячка со своего домена. Не начинайте со снятия отпечатка через canvas: его труднее оправдать, легче сломать, и он менее полезен, чем знание, выполнилась ли страница вообще.

Минимальный маячок

Отрисуйте на сервере случайный ID визита в страницу. Это ключ соединения, а не секрет:

<meta name="visit-id" content="a7f3c9e2">

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

<script> (() => { const visitId = document.querySelector('meta[name="visit-id"]')?.content ?? ""; const endpoint = "/api/visit"; const started = performance.now(); const storageWorks = () => { try { localStorage.setItem("__probe", "1"); localStorage.removeItem("__probe"); return true; } catch { return false; } }; const base = () => ({ visit_id: visitId, path: location.pathname, referrer: document.referrer, screen: `${screen.width}x${screen.height}`, viewport: `${innerWidth}x${innerHeight}`, language: navigator.language, languages: navigator.languages?.join(",") ?? "", timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, webdriver: navigator.webdriver === true, cores: navigator.hardwareConcurrency ?? 0, memory: navigator.deviceMemory ?? 0, touch: navigator.maxTouchPoints ?? 0, cookies: navigator.cookieEnabled, storage: storageWorks(), visibility: document.visibilityState, }); const send = (event, extra = {}) => { const body = JSON.stringify({ ...base(), event, ...extra }); if (navigator.sendBeacon) { navigator.sendBeacon(endpoint, new Blob([body], { type: "application/json" })); } else { fetch(endpoint, { method: "POST", body, keepalive: true, headers: { "Content-Type": "application/json" }, }); } }; const onLoad = () => send("load", { load_ms: Math.round(performance.now()) }); if (document.readyState === "complete") onLoad(); else addEventListener("load", onLoad, { once: true }); let interacted = false; for (const name of ["pointermove", "scroll", "keydown"]) { addEventListener(name, () => { interacted = true; }, { once: true, passive: true }); } setTimeout(() => send("alive", { interacted, elapsed_ms: Math.round(performance.now() - started), }), 5000); addEventListener("visibilitychange", () => { if (document.visibilityState === "hidden") { send("hide", { interacted, elapsed_ms: Math.round(performance.now() - started), }); } }); })(); </script>

О чём говорят поля

Признаки JavaScript и их слабые места
Признак О чём говорит Как ошибается
Нет маячка через 10 секунд Нет JavaScript, скрипт заблокирован или простой HTTP-клиент У пользователя отключён JavaScript; бот выполняет JavaScript
webdriver: true Фреймворк автоматизации оставил флаг включённым Флаг можно пропатчить; законная автоматизация тоже его ставит
Пустые languages или plugins Headless- или урезанное окружение Браузеры приватности их сокращают; значения можно подделать
touch: 0 при мобильном user-agent Несогласованное заявление Бывает режим компьютера, планшеты и гибридные устройства
Часовой пояс не совпадает со страной IP Прокси или несовпадающее окружение VPN, поездки и эмигранты
Нет взаимодействия через 5 секунд Загрузка скриптом Пользователь открыл страницу в фоновой вкладке; бот может синтезировать события
storage: false Хранилище заблокировано или окружение ограничено Настройки приватности и ограничения iframe
Быстрая загрузка и сразу скрытие Предзагрузка или бот Настоящие пользователи тоже уходят сразу
Хеш canvas или WebGL Личность устройства или автоматизации Подделывается, шумит и много требует от приватности
isTrusted: false Синтетическое событие CDP умеет создавать доверенные события; это не стена

navigator.webdriver — стандартное свойство, которое говорит, что user agent управляется автоматизацией. Это один полезный пример, а не приговор: MDN описывает его как признак, а современная автоматизация умеет его подавлять. То же относится к отсутствующим плагинам, пустым языкам и «headless-подобным» экранам. Статья F5 2015 года про PhantomJS — каталог пробелов окружения; конкретные приметы изменились, а принцип нет. Считайте каждую из них слабым признаком.

Снятие отпечатка идёт дальше: canvas, WebGL, звук, шрифты, рукопожатие TLS, порядок заголовков. Оно может быть мощным, но оно вероятностное, хрупкое и вторгается в приватность. Руководство W3C по снятию отпечатков считает это риском для приватности; руководство ICO по PECR считает доступ к хранилищу и устройству тем, что обычно требует согласия. Для обычной аналитики не делайте этого. Для защиты от мошенничества или безопасности опишите цель, минимизируйте данные, храните их недолго и получите юридическую проверку. Отпечаток — не человек; это оценка похожести.

Отпечатки транспорта (JA3/JA4) — сильный признак несовпадения: запрос, который заявляет Chrome, но договаривается о TLS как скрипт на Python, — не Chrome. Они требуют доступа на терминаторе TLS или CDN, который отдаёт отпечаток; в обычном журнале доступа их нет. Добавляйте их, только если управляете этим слоем.

Проверочные задачи (challenge) — это шаг, а не фундамент. Доказательство работы на JavaScript или CAPTCHA поднимают цену, но CAPTCHA обходится и мешает доступности. Используйте их для неоднозначных сессий, после более дешёвых проверок, и всегда оставляйте путь для тех проверенных роботов, которые вам нужны. Обзор методов обнаружения ботов от Azion описывает тот же порядок: репутация, проверка известных хороших, отпечаток, поведение, затем проверочная задача или блокировка.

Это гонка вооружений, и она несимметрична. Руководство по автоматизации Browserless 2026 года открыто описывает скрытные маршруты, которые убирают navigator.webdriver и вносят энтропию в canvas, WebGL и звук, домашние прокси, которые чинят репутацию IP, и решение CAPTCHA. Если ваш сайт — ценная цель, исходите из того, что упорный клиент пройдёт любую проверку на стороне клиента. Цель — не непобедимая стена, а сделать дешёвую атаку неудачной, а дорогую отправить на проверочную задачу или к человеку. Смотрите Browserless об обнаружении ботов.

Современные ИИ-агенты ещё сильнее усложняют слой браузера. Некоторые управляют настоящим Chrome, используют домашние соединения и подавляют navigator.webdriver; они могут пройти каждую отдельную проверку выше. Руководство cside 2026 года утверждает, что самый надёжный признак — поведение: детерминированные траектории мыши, чтение DOM всплесками, артефакты Chrome DevTools Protocol (CDP), отсутствие прокрутки до запроса. Оно же предлагает классифицировать намерение, а не блокировать по двоичному признаку, потому что потребительский агент может пытаться что-то купить. Здесь та же логика: оцените сессию, назовите намерение и выберите действие для каждого маршрута. Смотрите руководство cside по ИИ-агентам.

От признаков к решению

Оценка складывает слабые доводы. Веса ниже — пример, а не стандарт. Откалибруйте их на своей размеченной выборке; структура важнее чисел.

Иллюстративная модель оценки
Признак Пример веса Почему
Проверенный робот (список IP или FCrDNS) Переопределение в verified_crawler Твёрдая положительная личность; не добавляйте баллы известному боту
Известное имя бота, проверка не прошла +40 Выдача себя за другого или непроверяемое заявление
Проба служебного пути (/.env, /.git, /actuator) Переопределение в scanner Намерение не про контент
Больше 3 user-agent с одного IP за 10 минут +25 Сканер с несколькими личностями
Дата-центр или хостинг по ASN +15 Не решает: бывают VPN, облачные рабочие столы и CDN
Сессия только с HTML, 10+ запросов +15 Ресурсы не скачивались
CV промежутков < 0.3 на 20+ запросах +15 Машинный ритм
Доля 4xx > 30 % на 10+ запросах +15 Поведение сканера
Нет cookie между страницами +10 Клиент без состояния
Маячок JS с событием взаимодействия и 5 с на странице -30 Слабый довод в пользу человека
Согласованное окружение, cookie и ресурсы -20 Связная сессия браузера

Категории, а не двоичный признак

Порядок важен. Сначала переопределения, затем складываемые признаки, затем остаточные категории. Проверенного робота не должен «спасать» маячок JavaScript, а сканера не должен выручать браузерный user-agent. И наоборот: человека с отключённым JavaScript не стоит относить к ботам только потому, что маячка нет.

Разным решениям нужны разные пороги
Задача Действие Чего не делать
Аналитика Исключить проверенных роботов, сканеров и вероятную автоматизацию; оставить uncertain; агентов по инициативе человека показывать отдельно. Не выдавать «посетителей» за людей, когда в число входят роботы.
Ограничение частоты Для автоматических категорий пороги ниже; проверенным поисковым и ИИ-поисковым роботам дать те лимиты, которые вы задумали. Не загонять проверенного робота в 429, которых вы не хотели.
Контроль доступа Неоднозначные сессии отправлять на проверочную задачу; блокировать только сканеров с высокой уверенностью или вредное поведение. Не блокировать неопределённые сессии и целые облачные ASN.
Видимость в ИИ Разрешать нужных ИИ-роботов; проверять, что они получают 200, а не 403 или 429. Не блокировать каждый ИИ-токен рефлекторно; агенты по запросу пользователя могут приводить клиентов.

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

Держите корзину uncertain. Это не провал, это честность. Классификатор, который никогда не говорит «неизвестно», переоценивает свои силы, а жёсткая блокировка неопределённой сессии — это путь, которым ложные срабатывания становятся обращениями в поддержку.

Приватность, ложные срабатывания и правила

Журналы и маячки обрабатывают персональные данные. IP-адрес может быть персональными данными; cookie или отпечаток устройства может быть онлайн-идентификатором. В ЕС и Великобритании PECR/ePrivacy требует согласия на хранение информации на устройстве пользователя или доступ к ней, с ограниченными исключениями, а к обработке применяется GDPR. Руководство ICO про cookie и похожие технологии — отправная точка, а не юридическая консультация.

Минимизируйте то, что собираете:

Ложные срабатывания — не пограничные случаи:

Проектируйте с учётом этого. Жёсткая блокировка по признаку «нет JavaScript» заденет некоторых людей. Блокировка по ASN дата-центра заденет некоторых клиентов. Сначала проверочная задача, а блокировка — только при плохом поведении, в котором вы уверены, и дайте людям способ сообщить о ложном срабатывании.

Правила — отдельное решение, не часть обнаружения:

Рабочий порядок действий

Начните с одной недели журналов и одного вопроса: сколько запросов сделали не люди? Работающая последовательность:

  1. Наведите порядок в формате журнала. Убедитесь, что настоящий IP клиента переживает CDN или прокси. Записывайте user-agent, referer, статус, байты и время; добавьте длительность, если можете.
  2. Соберите словарь проверенных ботов. Для каждого токена: поставщик, назначение, URL списка IP, суффикс rDNS и дата последней проверки. Обновляйте списки ежедневно или еженедельно.
  3. Разбейте на сессии. Окно неактивности 30 минут. Предпочитайте cookie своего домена; при её отсутствии опирайтесь на IP плюс user-agent плюс время.
  4. Обогатите. Добавьте ASN, тип сети, rDNS, грубую геолокацию, семейство user-agent и класс пути.
  5. Посчитайте признаки. Доля ресурсов, доля ошибок, число разных user-agent, ритм, глубина, входной путь и непрерывность cookie.
  6. Разметьте выборку. Начните с проверенных роботов и очевидных сканеров; затем размечайте неоднозначные сессии, не глядя на оценку.
  7. Оцените и задайте пороги. Отделите аналитику от контроля доступа. Оставьте корзину uncertain и путь для обжалования.
  8. Добавьте маячок. Начните с части страниц. Соединяйте по ID визита или по IP, user-agent и времени. Измерьте, что он добавляет, прежде чем включать его везде.
  9. Смотрите и перекалибруйте. Первый месяц — раз в неделю, затем раз в месяц или квартал. Следите за ложными срабатываниями и заблокированными роботами.

Шаблон недельного отчёта, который держит категории честными:

category requests share verified search crawler ... ... verified AI crawler ... ... declared automation ... ... scanner ... ... likely automated ... ... uncertain ... ... human-initiated agent ... ... likely human ... ...

Заполняйте его тем же классификатором, который принимает решения. Не ведите вторую таблицу с другим определением «человека».

Если делаете только одно — проверьте IP, прежде чем доверять имени. Если делаете два — добавьте проверку проб служебных путей. Оба дешёвые, и вместе они убирают большую часть шума.

Источники и что почитать дальше

Статьи ниже легли в основу этого руководства. Списки поставщиков и способы проверки меняются; сверяйтесь с текущей документацией, прежде чем полагаться на диапазон или токен.

Журналы, поведение и картина 2026 года

JavaScript и снятие отпечатков

Проверка и реализация

Ссылки на Stack Overflow, Меланину, vc.ru, WorkOS, Azion, Web Scraper и cside — источники, предложенные для этой статьи; остальные — первичные документы поставщиков и стандартов, по которым проверялись утверждения.

Автор статьи: Arthur Isaev

Изображение баннера