Как пустить ИИ-ботов на сайт и не пустить тех, кто ими притворяется

Обсудить
Как пустить ИИ-ботов на сайт и не пустить тех, кто ими притворяется
Реклама. АО «ТаймВэб». erid: 2W5zFHeemSH

Когда боты ChatGPT приходят на сайт с зарубежных адресов, они делают много запросов подряд и ничего не рендерят – для защиты от ботов это поведение скрапера. Боты получают 403, страница не попадает в источники ответов, а в логах всё выглядит как отбитая атака, и никто ничего не замечает.

Лечится это белым списком: адреса, с которых ходят настоящие боты, исключаются из общих правил. Мешают две вещи. Первая – список живой: вендоры добавляют и убирают подсети без анонсов, изредка сразу тысячами адресов. В августе Apple расширила пул Applebot на несколько тысяч адресов, и все статические списки, написанные до этого, разом перестали быть полными. Вторая – заметная доля заходов с User-Agent ИИ-бота сделана вовсе не ботом: имя подделывается одной строкой.

Дальше – как собрать белый список скриптом из официальных источников, как отличить настоящего бота от самозванца по обратной зоне, как превратить всё это в конфиги nginx и iptables и как проверить по логам, что оно работает.

Зачем сайту белый список адресов

Задача выглядит просто: не мешать ИИ-ботам читать сайт. На практике мешают три вещи:

1. Защита от ботов. Cloudflare, антифрод-прослойки и обычный `fail2ban` режут запросы по поведению, а не по имени: правило срабатывает раньше, чем кто-нибудь смотрит на User-Agent. Отличить обход ChatGPT от парсера-скрапера по одному только поведению нельзя – много запросов, нет рендеринга, нет мыши и там, и там.

2. Rate limiting. Лимит в 30 запросов с адреса в минуту звучит безобидно, пока обход не приходит с одной подсети и не упирается в него на десятой странице.

3. Геофильтры. Часть проектов режет трафик из-за рубежа целиком. Все перечисленные боты ходят с зарубежных адресов.

Отсюда потребность в белом списке – перечне доверенных диапазонов, которые исключаются из общих правил (в документации вендоров он называется allowlist).

Где лежат официальные фиды

Четыре вендора публикуют диапазоны так, чтобы ИИ спокойно их читал, в одном и том же формате – JSON со списком префиксов:

Бот

Фид

Назначение

Applebot

`search.developer.apple.com/applebot.json`

Siri, Spotlight, обучение моделей Apple

GPTBot

`openai.com/gptbot.json`

обход для обучения

OAI-SearchBot

`openai.com/searchbot.json`

обход для поисковой части ChatGPT

ChatGPT-User

`openai.com/chatgpt-user.json`

заход по действию пользователя

PerplexityBot

`perplexity.ai/perplexitybot.json`

обход Perplexity

Формат одинаковый, поэтому парсер пишется один раз:

import json, urllib.request, ipaddress

UA = {"User-Agent": "allowlist-builder/1.0"}
FEEDS = {
    "Applebot":      "https://search.developer.apple.com/applebot.json",
    "GPTBot":        "https://openai.com/gptbot.json",
    "OAI-SearchBot": "https://openai.com/searchbot.json",
    "ChatGPT-User":  "https://openai.com/chatgpt-user.json",
    "PerplexityBot": "https://www.perplexity.ai/perplexitybot.json",
}

def fetch(url):
    req = urllib.request.Request(url, headers=UA)
    data = json.load(urllib.request.urlopen(req, timeout=25))
    out = []
    for p in data.get("prefixes", []):
        cidr = p.get("ipv4Prefix") or p.get("ipv6Prefix")
        if cidr:
            out.append(cidr)
    return out

allow = {name: fetch(url) for name, url in FEEDS.items()}
for name, cidrs in allow.items():
    ips = sum(ipaddress.ip_network(c).num_addresses for c in cidrs if ":" not in c)
    print(f"{name:15} {len(cidrs):4d} префиксов, {ips:7d} адресов IPv4")

Вывод на 20 августа 2026:

Applebot          33 префиксов,    7056 адресов IPv4
GPTBot            21 префиксов,    3472 адресов IPv4
OAI-SearchBot     35 префиксов,    2496 адресов IPv4
ChatGPT-User     204 префиксов,   36016 адресов IPv4
PerplexityBot      8 префиксов,      18 адресов IPv4

Что видно из этих чисел

Размер пула говорит о назначении бота больше, чем его документация

Размер пула говорит о назначении бота больше, чем его документация.

Разброс у меня вышел на целых три порядка, и он объясняется саим устройством ботов.

PerplexityBot – 18 адресов. Восемь префиксов, почти все на /29 и /30. Это плановый обход с небольшой фермы: предсказуемый, легко белится, легко ловится по IP.

ChatGPT-User – 36 016 адресов, 204 префикса. Это не обход, а заход по действию человека: пользователь задал вопрос, система пошла за конкретной страницей прямо сейчас. Такие запросы идут из инфраструктуры, обслуживающей живых людей, отсюда объём.

Из этого следует практическое правило: ChatGPT-User блокировать нельзя ни при каких настройках. За ним стоит человек, который прямо сейчас читает ответ про вас. GPTBot закрыть можно осознанно, если не хотите отдавать контент в обучение, – на попадание в ответы это влияет косвенно. А вот закрытие OAI-SearchBot и ChatGPT-User убирает вас из ответов напрямую.

Applebot – 7 056 адресов. После августовского расширения это второй по величине пул. Apple использует его и для Siri со Spotlight, и для обучения своих моделей.

Одного списка IP недостаточно

IP-адрес подделывается на уровне заголовка: любой скрапер может представиться `GPTBot` в User-Agent. Поэтому белый список по IP решает только половину задачи, а вторую половину решает обратная зона.

Проверка выглядит так: берём адрес, получаем PTR-запись, проверяем, что домен принадлежит вендору, и делаем прямой запрос обратно – совпал ли адрес.

#!/usr/bin/env bash
# Проверка подлинности бота: forward-confirmed reverse DNS
ip="$1"
host_name=$(dig +short -x "$ip" | sed 's/\.$//')
[ -z "$host_name" ] && { echo "$ip: PTR отсутствует – подделка"; exit 1; }

case "$host_name" in
  *.applebot.apple.com|*.crawl.apple.com) vendor="Apple" ;;
  *.openai.com)                            vendor="OpenAI" ;;
  *.perplexity.ai|*.perplexity.com)        vendor="Perplexity" ;;
  *) echo "$ip: $host_name – чужой домен"; exit 1 ;;
esac

back=$(dig +short "$host_name" | head -1)
if [ "$back" = "$ip" ]; then
  echo "$ip: подтверждён ($vendor, $host_name)"
else
  echo "$ip: PTR ведёт на $host_name, но обратный адрес $back – подделка"
  exit 1
fi

Связка из двух проверок закрывает обе истории: фид отвечает на вопрос «этот адрес вообще принадлежит вендору», обратная зона – «этот запрос действительно оттуда».

Как превратить список в конфиг nginx и правила ipset

Дальше список превращается в то, что применяется на сервере. Для nginx это карта доверенных адресов:

def nginx_geo(allow, path="ai-bots.conf"):
    lines = ["# Сгенерировано автоматически, правки будут перезаписаны",
             "geo $ai_bot {", "    default 0;"]
    for name, cidrs in allow.items():
        lines.append(f"    # {name}")
        lines += [f"    {c} 1;" for c in cidrs]
    lines.append("}")
    open(path, "w").write("\n".join(lines) + "\n")

def ipset_rules(allow, path="ai-bots.ipset"):
    lines = ["create ai_bots hash:net family inet -exist"]
    for cidrs in allow.values():
        lines += [f"add ai_bots {c} -exist" for c in cidrs if ":" not in c]
    open(path, "w").write("\n".join(lines) + "\n")

В конфиге nginx переменная используется прямо в лимитах:

include /etc/nginx/conf.d/ai-bots.conf;

map $ai_bot $limit_key {
    1 "";              # доверенный бот – вне лимита
    default $binary_remote_addr;
}

limit_req_zone $limit_key zone=common:10m rate=30r/m;

Пустой ключ выводит запрос из-под ограничения, не требуя отдельного `location` и дублирования правил.

Как это держать в актуальном состоянии

Не перезаписывать конфиг вслепую. Если фид недоступен или вернул пустой список, скрипт должен оставить прежний файл и написать в лог. Иначе одна сетевая ошибка выносит из белого списка всех ботов сразу.

Сравнивать с последним замером. Разница списков – самая полезная строка в логе: видно, что вендор добавил подсеть, и видно, когда именно. Именно так расширение Applebot заметно без чтения новостей.

Проверять применение. После генерации – `nginx -t` и перезагрузка конфигурации, а не рестарт: перезагрузка не рвёт открытые соединения.

import subprocess, json, pathlib

snapshot = pathlib.Path("allowlist.json")
prev = json.loads(snapshot.read_text()) if snapshot.exists() else {}

if all(len(c) for c in allow.values()):          # ни один фид не пустой
    for name in allow:
        added = set(allow[name]) - set(prev.get(name, []))
        removed = set(prev.get(name, [])) - set(allow[name])
        if added or removed:
            print(f"{name}: +{len(added)} −{len(removed)}")
    snapshot.write_text(json.dumps(allow, indent=2))
    nginx_geo(allow, "/etc/nginx/conf.d/ai-bots.conf")
    subprocess.run(["nginx", "-t"], check=True)
    subprocess.run(["nginx", "-s", "reload"], check=True)
else:
    print("пустой фид – конфиг не тронут")
Applebot и Applebot-Extended: разные вещи в одном robots.txt

Отдельная путаница, на которую стоит потратить абзац. У Apple два токена в `robots.txt`, и они управляют разными вещами.

`Applebot` – сам обход. Закрыв его, вы выпадаете из Siri и Spotlight.

`Applebot-Extended` – не отдельный бот, а сигнал о том, можно ли использовать уже собранные данные для обучения моделей Apple. Он не влияет на обход и на попадание в поисковые продукты: страницы продолжают собираться, просто не идут в обучение.

User-agent: Applebot
Allow: /

User-agent: Applebot-Extended
Disallow: /

Такая пара означает: индексируйте для поиска и Siri, но не учите на нас модели. Обратная комбинация смысла не имеет – закрыв `Applebot`, вы автоматически лишаете смысла второй токен.

Похожее деление есть у OpenAI: `GPTBot` отвечает за обучение, `OAI-SearchBot` и `ChatGPT-User` – за поисковую часть и заходы пользователей. Решение «закрыть ИИ-ботов» одной строкой почти всегда бьёт не туда, куда планировалось.

Как проверить, что белый список действительно работает

Собранный конфиг ничего не гарантирует, пока вы не увидели подтверждённые заходы в логах. Проверка занимает одну команду и одну ночь ожидания.

# Кто из ИИ-ботов приходил за сутки и сколько запросов сделал
grep -aiE "GPTBot|OAI-SearchBot|ChatGPT-User|PerplexityBot|Applebot|ClaudeBot" \
     /var/log/nginx/access.log \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

Первая колонка – число запросов, вторая – адрес. Дальше каждый адрес из верхушки прогоняется через проверку обратной зоны из предыдущего раздела: так отделяются настоящие боты от тех, кто просто подставил себе чужой User-Agent. По моему опыту подделок в этом списке заметная доля, и без проверки статистика по ИИ-ботам получается завышенной.

Отдельно стоит посмотреть коды ответов: если подтверждённый бот стабильно получает 403 или 429, значит правило где-то выше по стеку – в облачной защите или на балансировщике, и локальный конфиг nginx до него не доходит.

# Коды ответов для подтверждённого адреса бота
grep -a "203.0.113.10" /var/log/nginx/access.log \
  | awk '{print $9}' | sort | uniq -c | sort -rn

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

Чего этот подход не решает

Фиды публикуют не все. У Anthropic машиночитаемого списка диапазонов для `ClaudeBot` я не нашёл – остаётся проверка по обратной зоне и по User-Agent. То же с российскими системами: у Яндекса своя схема проверки роботов, у GigaChat публичного фида нет.

Поэтому белый список по IP – не полное решение, а первый слой. Второй слой – проверка обратной зоны, третий – здравые лимиты, при которых легальный обход не упирается в потолок на десятой странице.

И последнее: белый список не делает вас видимым в ответах. Он только убирает препятствие. Если после его внедрения в логах по-прежнему нет ни одного подтверждённого захода ИИ-бота, дело не в фильтрах, а в том, что модели просто нечего у вас читать.

Наши постоянные авторы и читатели делятся лайфхаками, основанными на личном опыте. Полная свобода самовыражения.

Комментарии

С помощью соцсетей
У меня нет аккаунта Зарегистрироваться
С помощью соцсетей
У меня уже есть аккаунт Войти
Инструкции по восстановлению пароля высланы на Ваш адрес электронной почты.
Пожалуйста, укажите email вашего аккаунта
Ваш баланс 10 ТК
1 ТК = 1 ₽
О том, как заработать и потратить Таймкарму, читайте в этой статье
Чтобы потратить Таймкарму, зарегистрируйтесь на нашем сайте