Перейти к содержанию

abuse-guard: Автоматическая блокировка злоумышленных клиентов по частоте ошибочных ответов

Установка

Вы можете установить этот модуль в любом дистрибутиве на основе RHEL, включая, но не ограничиваясь:

  • RedHat Enterprise Linux 7, 8, 9 и 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-abuse-guard
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-abuse-guard

Включите модуль, добавив следующую строку в начало /etc/nginx/nginx.conf:

load_module modules/ngx_http_abuse_guard_module.so;

В этом документе описывается nginx-module-abuse-guard v2.1.0, выпущенный 03 сентября 2026 года.


Ваш журнал ошибок — это признание. Abuse Guard читает его в реальном времени и блокирует злоумышленников.

Каждый сканер, фаззер и бот для подбора учетных данных оставляет один и тот же след: шквал 404 в поисках скрытых путей, 403 от запертых дверей, бесконечная череда неудачных запросов. Abuse Guard отслеживает коды состояния, которые ваш сервер фактически возвращает, определяет клиентов, чей трафик состоит в основном из ошибок, и блокирует их — решение принимается внутри рабочего процесса NGINX, непосредственно для запроса, за несколько микросекунд. Никаких сайдкаров. Никаких сборщиков логов. Никакого скриптового слоя. Просто скомпилированный C, выполняющий одну задачу исключительно хорошо.

Технические характеристики

Триггер Частота ошибочных ответов на клиента, которую вы выбираете (по умолчанию 403/404)
Действие Блокировка на время — жесткий бан на фиксированный период, а не ограничение скорости
Точка принятия решения Фаза preaccess в NGINX, до выполнения любого обработчика или обращения к апстриму
Модель памяти Фиксированное количество байт на клиента, не зависящее от порога → масштаб ботнета
Режим кластера Опциональная репликация банов между узлами через Redis / Valkey
Устойчивость Опциональные снапшоты при выходе сохраняют активные баны между перезапусками
Занимаемые ресурсы Один автономный модуль; по умолчанию ноль зависимостей во время выполнения
Платформы RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux
##

Проблема, которую он устраняет

Легитимные посетители почти никогда не создают шквал ошибок. Злоумышленники создают почти ничего, кроме них — эта асимметрия и есть вся суть. Сканер уязвимостей, обходящий ваше дерево каталогов, — это стена 404. Бот, проверяющий админ-эндпоинты, — это стена 403. Брутфорс — это стена неудач.

Ограничители скорости относятся к такому трафику как к любому другому: они замедляют всех по объему запросов и впускают нарушителя обратно в ту же секунду, как только он снижает интенсивность. Abuse Guard делает наоборот. Он полностью игнорирует корректный трафик и резервирует свой единственный ответ — реальный, ограниченный по времени бан — для клиентов, определяемых их ошибками.

Используйте ограничитель скорости для управления нагрузкой. Используйте Abuse Guard для изгнания злоупотреблений.

Как принимается решение о бане

Три движущиеся части, все внутри рабочего процесса:

1 · Протекающий счетчик, на каждого клиента. Каждая идентичность клиента несет одно небольшое число в разделяемой памяти. Каждая подходящая ошибка добавляет одно очко по умолчанию или вес, который вы назначаете этому статусу; счетчик непрерывно убывает со скоростью порог ÷ интервал в секунду. Короткая, резкая вспышка переваливает за линию; медленная капель — никогда. Важно, что этот счетчик — одна запись фиксированного размера, независимо от того, насколько высоко вы установили порог, поэтому одна зона с комфортом отслеживает десятки тысяч различных исходных адресов, которые ботнет обрушивает на вас.

2 · Жесткий дедлайн. В момент, когда счетчик пересекает ваш порог, клиент получает временную метку blocked_until. До этого момента он просто исчезает — каждый запрос отклоняется на фазе preaccess, до того как NGINX потратит цикл на маршрутизацию, файлы или апстримы. Отказ — это самый дешевый из возможных исходов.

3 · Корректный с точки зрения конфиденциальности отказ. Забаненные клиенты получают 429 Too Many Requests (код на ваш выбор) с пометкой, запрещающей любому общему кэшу сохранить его и выдать наказание одного клиента другому, а также с Retry-After, сообщающим честным клиентам, когда возвращаться.

Идентичности сворачиваются в дайджест фиксированного размера, поэтому использование такого объемного ключа, как $request_uri или заголовок, стоит ровно столько же памяти, сколько и ключ по IP.

Работает менее чем за минуту

Abuse Guard поставляется как предварительно скомпилированный, подписанный модуль из репозитория GetPageSpeed — просто установите его, без необходимости в инструментарии сборки.

sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard

Подключите его:

load_module modules/ngx_http_abuse_guard_module.so;

http {
    abuse_guard_zone zone=clients:10m;     # одна зона разделяемой памяти

    server {
        location / {
            abuse_guard zone=clients;      # применять здесь
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

Эти настройки по умолчанию банят любой IP, который возвращает 100 ответов 403/404 в течение 5-минутного окна, на один час. Ужесточите или ослабьте любое из этих чисел ниже.

Конфигурация

Abuse Guard — это четыре директивы. Первая объявляет политику; остальные применяют ее, освобождают людей от нее и (опционально) распространяют ее между машинами.

Объявление политики — abuse_guard_zone

Директива уровня http. Она выделяет одну зону разделяемой памяти и задает политику, которая ей управляет. Задайте столько параметров, сколько хотите, — имя зоны и ее размер — единственное, что вы обязаны указать; разумные значения по умолчанию заполнят остальное (значения, показанные ниже, — это именно эти значения по умолчанию).

abuse_guard_zone  zone=clients:10m             имя + размер (единственное обязательное)
                  key=$binary_remote_addr      кто такой "один клиент"
                  statuses=403,404             какие ответы добавляют к счетчику
                  interval=300s                окно подсчета
                  threshold=100                счет в этом окне  бан
                  block=60m;                   как долго действует бан

zone=clients:10m — это идентичность и бюджет политики: имя, на которое вы ссылаетесь из abuse_guard, и размер разделяемой памяти. Около 10 МБ отслеживают порядка ста тысяч активных клиентов.

Все остальное — необязательная настройка:

  • key — выражение, определяющее одного клиента. Любая переменная NGINX; по умолчанию $binary_remote_addr — ключ по исходному IP. Запрос, ключ которого оказывается пустым, полностью пропускается (удобно с map, см. ниже).
  • statuses — ответы, которые добавляют к счетчику. Простой код или диапазон имеет вес 1, сохраняя исходный синтаксис: statuses=403,404,500-599. Добавьте :вес, чтобы ответ потреблял больше того же бюджета, например statuses=404,401:5,500-599:2. Веса — целые числа от 1 до 1024, и диапазон применяет свой вес к каждому статусу, который он покрывает. Повторение или пересечение статуса с тем же весом безвредно; конфликтующие веса вызывают ошибку nginx -t. По умолчанию остается 403,404.
  • interval — окно, в течение которого счетчик затухает (по умолчанию 300s). Всплеск внутри него вызывает бан; медленная капель, растянутая шире, никогда не накапливается.
  • threshold — сколько очков счетчика в этом окне пересекают линию, до 1024 (по умолчанию 100). Тяжелый ответ может израсходовать оставшийся бюджет и вызвать бан немедленно.
  • block — как долго сработавший клиент остается заблокированным (по умолчанию 60m).
  • inactive — как долго бездействующий клиент задерживается в памяти перед удалением (по умолчанию max(1h, interval, block); любое явное значение должно быть не меньше, чем оба interval и block).
  • redison для репликации банов этой зоны по кластеру (см. ниже); по умолчанию off.
  • persist — путь к файлу, куда активные баны выгружаются при чистом выходе рабочего процесса и загружаются при запуске.
  • persist_secret — в сборках с поддержкой подписанных снапшотов — шестнадцатеричный ключ, добавляющий аутентификацию HMAC-SHA256, чтобы измененный файл был отклонен.

Почему 5xx исключен по умолчанию: ошибка сервера обычно — дело вашей стороны, и ее подсчет позволил бы одному нестабильному бэкенду добиться бана для невинных посетителей. Добавляйте statuses=403,404,500-599 только когда вы намеренно хотите воздействовать на клиентов, вызывающих ошибки сервера.

Применение — abuse_guard

Действует в блоках http, server и location, так что вы можете защитить весь сайт или только эндпоинты, привлекающие злоупотребления. Укажите имя зоны, чтобы включить ее; напишите abuse_guard off; во вложенной области, чтобы выключить ее обратно.

location /wp-login.php {
    abuse_guard zone=clients status=429 log_level=warn;
}
  • zone — зона (объявленная выше), чья политика применяется здесь.
  • status — код, который получает забаненный клиент, в диапазоне 400599 (по умолчанию 429).
  • dry_runon для наблюдения без применения: вердикт записывается в журнал, но бан не выписывается. По умолчанию выключен.
  • log_level — насколько подробно журналировать каждое решение: info, notice (по умолчанию), warn или error.

Развертывайте без страха с dry_run=on. Он записывает каждый бан, который выдал бы, не затрагивая состояние, так что вы можете откалибровать пороги на живом трафике — даже рядом с применяющим location в той же зоне — а затем переключить в боевой режим.

Освобождение хороших — abuse_guard_allow

Контекст: http · server · location · повторяемая, наследуется вниз.

abuse_guard_allow 127.0.0.0/8;
abuse_guard_allow 10.0.0.0/8 192.168.0.0/16;

Перечисленные клиенты никогда не учитываются и не банятся. Сопоставление происходит по истинному адресу соединения, поэтому оно работает совместно с realip. Это также способ защитить проверенных поисковых краулеров: разрешите опубликованные диапазоны Googlebot / Bingbot, чтобы бот, перемалывающий устаревшие URL (и набирающий 404), никогда не был пойман.

Обмен банами по кластеру — abuse_guard_redis

Контекст: http

abuse_guard_redis host=10.0.0.5 password=… ;   # tls://host для TLS
abuse_guard_zone  zone=clients:10m redis=on;

Направьте каждый узел на один Redis или Valkey, включите redis=on, и бан, полученный на любой машине, распространится на все. По умолчанию: port=6379, db=0, prefix=ag_, timeout=100ms. О том, как сохраняется скорость, — в следующем разделе.

SELinux: в системах с принудительным режимом (RHEL, Rocky, AlmaLinux) ядро останавливает NGINX от открытия соединения с Redis, пока вы не разрешите это один раз — setsebool -P httpd_can_network_connect 1. Пропустите это, и репликация молча ничего не будет делать, пока локальное применение продолжает работать как обычно.

Один бан, на каждом узле — без замедления ни одного запроса

За балансировщиком нагрузки бан на одном сервере — это театр: атакующий просто попадает на другой узел. Abuse Guard закрывает этот пробел не помещая Redis в путь обработки запроса.

Каждый узел решает локально и считает локально. В момент выдачи бана он рассылает этот единственный факт по кластеру и сохраняет устойчивую копию. Каждый другой узел импортирует его в течение миллисекунд, а любой узел, который был офлайн, синхронизируется в момент переподключения. Поскольку применение всегда обслуживается из собственного состояния в памяти каждого узла, запрос посетителя никогда не ждет сетевого往返 — единственная цена кластеризации в том, что свежезабаненный атакующий блокируется по всему кластеру на одно сердцебиение позже, а не мгновенно.

Redis здесь — односторонний сигнальный колокол, а не разделяемый реестр, к которому обращаются за каждый запрос, — поэтому медленный или отсутствующий Redis никогда не добавит задержку вашему трафику. Запускайте его в частной сети и относитесь к нему как к привилегированному: любой, кто может писать в него, может выдавать баны.

Баны, переживающие перезапуск

Укажите зоне путь к файлу, и активные баны будут выгружены при чистом выходе рабочего процесса, а затем восстановлены при запуске. Перезагрузки и штатные перезапуски сохраняют текущие баны без запуска периодического писателя всей зоны. Внезапный сбой процесса или машины может потерять баны, выданные с момента последнего чистого выхода; применение по-прежнему работает в режиме fail-open.

abuse_guard_zone zone=clients:10m
                 persist=/var/lib/nginx/abuse_guard/clients.state
                 persist_secret=00112233445566778899aabbccddeeff;

Компактный снапшот содержит только дайджесты идентичностей и сроки банов. CRC32 обнаруживает повреждения, а атомарное переименование не позволяет частичным записям попасть в рабочий путь. Сборки с поддержкой подписанных снапшотов могут дополнительно аутентифицировать его с помощью persist_secret. Держите каталог доступным на чтение только пользователю рабочего процесса.

Просмотр всех его решений

Три переменные раскрывают вердикт Abuse Guard для ваших журналов и конфигурации:

Переменная Значение
$abuse_guard_status BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN
$abuse_guard_count Текущий взвешенный счет, округленный до целого очка.
$abuse_guard_blocked_until Время Unix, когда бан снимается, или 0.
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

Ключ за CDN или прокси? Никогда не доверяйте сырому X-Forwarded-For. Пусть realip сначала определит реального клиента, затем используйте ключ $binary_remote_addr:

set_real_ip_from 10.0.0.0/8;
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

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

Создан для доверия в продакшене

Abuse Guard соответствует стандарту, намного превышающему «это компилируется». Каждое изменение проходит испытания AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, статический анализ и непрерывный фаззинг его парсеров и формата на диске. Его опциональные зависимости — кластеризация и подписанные снапшоты — по замыслу работают по принципу best-effort: если Redis или диск ведут себя некорректно, применение тихо продолжается из локальной памяти. Ваш трафик никогда не находится в заложниках у зависимости.

Получите Abuse Guard

Abuse Guard — это коммерческий модуль NGINX от GetPageSpeed LLC, поставляемый с постоянными обновлениями и поддержкой через подписку GetPageSpeed.

© GetPageSpeed LLC. Все права защищены.