SecRadarПоиск

НАСТРОЙКА И ПРОВЕРКА

WAF для NGINX: ModSecurity, правила CRS и переход к блокировке

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

Редакция SecRadar · 2 октября 2026

Можно ли включить WAF в NGINX?

Да. Один из вариантов — NGINX с коннектором ModSecurity v3 и набором правил OWASP Core Rule Set (CRS). NGINX принимает и проксирует запрос, ModSecurity проверяет его, а CRS задаёт признаки подозрительной активности. Обычная установка NGINX сама по себе этих проверок не добавляет.

В этой статье используем отдельный reverse proxy перед приложением. Это позволяет сначала проверить фильтрацию на стенде, не пересобирая действующий веб-сервер. Подключение движка и правил описано в руководстве установки CRS и документации коннектора ModSecurity для NGINX.

Не путайте два проекта.

Коммерческий модуль NGINX ModSecurity WAF для NGINX Plus завершил жизненный цикл 31 марта 2024 года. Это не означает прекращение открытого ModSecurity или CRS. Для старой инструкции сначала проверьте, какой именно продукт, пакет и способ поддержки в ней описаны. Статус модуля у NGINX · FAQ проекта ModSecurity.

Три способа подключить WAF к NGINX

СхемаЧто меняетсяЧто проверить
Модуль в существующем NGINXКоннектор и движок работают вместе с вашим сервером.Совместимость бинарного модуля, сборки NGINX и библиотек; порядок обновления.
Отдельный reverse proxyЗапросы идут через новый узел WAF, затем в приложение.TLS, исходный IP, тайм-ауты и запрет прямого доступа к backend.
Готовый WAF-продуктПодключается нода или агент по схеме производителя.Поддерживаемые версии NGINX/Angie, лицензии, резервирование и ограничения модулей.
Схема учебного стенда — только HTTP на локальном компьютере
  1. curl127.0.0.1:18080
  2. NGINX + WAFModSecurity + CRS
  3. Приложение-заглушкаВнутренняя сеть Docker

Из контейнеров наружу опубликован только порт WAF, привязанный к loopback. Backend не имеет опубликованного порта. В рабочей инфраструктуре аналогичное ограничение нужно обеспечить маршрутизацией и сетевыми правилами: иначе приложение можно открыть в обход фильтра.

Локальный стенд: NGINX, ModSecurity и CRS

Нужны Docker Engine с Compose v2 либо Docker Desktop в режиме Linux-контейнеров, Python 3 и свободный порт 18080. В архиве — Compose-конфигурация, небольшое тестовое приложение, контрольное правило и сценарий проверок. Образы закреплены по digest; теги latest при запуске не используются.

Скачать конфигурацию стенда и тесты (ZIP) →

Статус примера

Параметры сверены с официальными исходниками и метаданными образов 2 октября 2026 года; конфигурация прошла статические проверки. Полный запуск NGINX + ModSecurity редакцией пока не выполнен. Ответы ниже — критерии проверки на вашем стенде, а не опубликованные результаты испытаний.

Состав архива: compose.json, backend.py, lab-rules.conf, smoke.py и пример исключения. JSON используется как формат Compose-файла. В метаданных выбранного образа указан NGINX 1.30.5; фактические версии движка и CRS сохраните после запуска. Их нельзя определять только по имени тега.

1. Распакуйте архив и проверьте конфигурацию

unzip nginx-lab.zip
cd secradar-waf-lab
docker compose -f compose.json config --quiet
docker compose -f compose.json pull
MODSEC_RULE_ENGINE=DetectionOnly docker compose -f compose.json up -d
docker compose -f compose.json exec -T waf nginx -t

Команды рассчитаны на shell Linux/macOS. Не используйте каталог с действующим Compose-проектом: у стенда собственное имя secradar-waf-lab. Если контейнер не стартовал, сначала прочитайте docker compose -f compose.json logs waf; не переходите к тестам до устранения ошибки.

2. Зафиксируйте состав

docker compose -f compose.json exec -T waf nginx -V
docker compose -f compose.json exec -T waf sh -c \
  'ls /usr/local/modsecurity/lib/libmodsecurity.so.*'
docker compose -f compose.json exec -T waf sh -c \
  'grep -m 1 OWASP_CRS /opt/owasp-crs/rules/REQUEST-901-INITIALIZATION.conf'
docker compose -f compose.json images

Сохраните вывод рядом с результатами. Digest фиксирует образ, но не заменяет регулярные обновления и повторные проверки. Полные идентификаторы обоих образов записаны в images.json внутри архива.

3. Начните с DetectionOnly

В этом режиме ModSecurity продолжает проверять запросы, но его блокирующие действия не исполняются. Это не выключает ограничения самого NGINX и не гарантирует ответ 200: например, недоступный backend всё равно приведёт к ошибке. Значение Off имеет другой смысл — отключение обработки движком. Описание SecRuleEngine.

Ключевые настройки стенда: адрес backend, режим движка, уровень паранойи 1 и входящий порог аномальности 5. Полный файл с закреплёнными образами находится в архиве. Пути монтирования относятся к выбранному образу CRS, а не к любой установке NGINX. Документация контейнера CRS.

Как проверить, что запрос действительно проходит через WAF

Обычный ответ 200 ещё не подтверждает работу фильтра. В стенде есть безвредный маркер secradar_waf_test=1 и отдельное правило с ID 100100. Оно позволяет проверить цепочку обработки, не полагаясь на конкретную сигнатуру атаки.

curl -i 'http://127.0.0.1:18080/'
curl -i 'http://127.0.0.1:18080/?secradar_waf_test=1'
docker compose -f compose.json logs --no-color waf

В DetectionOnly оба запроса должны дойти до заглушки: ожидаются 200, заголовок X-Lab-Backend: secradar и событие с ID 100100 для маркера. Заглушка не исполняет полученные данные и не возвращает их в HTML.

Переключение на блокировку

MODSEC_RULE_ENGINE=On docker compose -f compose.json up -d --force-recreate waf
curl -i 'http://127.0.0.1:18080/'
curl -i 'http://127.0.0.1:18080/?secradar_waf_test=1'

Ожидаемый результат: обычный запрос — 200, маркер — 403 без заголовка backend. В журнале должен быть именно ID 100100: ответ 403 без связанного события мог прийти из другого компонента. Контрольное правило — учебное; оно не проверяет полноту CRS и не предназначено для рабочего приложения.

ПроверкаКритерий
Обычный GET200 и метка backend в обоих режимах.
Маркер в query string200 в DetectionOnly; 403 и ID 100100 в On.
Корректный JSON200; тело запроса прочитано приложением.
Маркер внутри JSON403 в On. Проверяется разбор тела, а не только URL.
Небольшой файлОбычная multipart-загрузка проходит в обоих режимах.
Возврат в DetectionOnlyМаркер снова доходит до backend; наблюдение остаётся включённым.

Эти проверки собраны в python3 smoke.py. Сценарий работает только с локальным адресом, записывает результаты в results.json и журнал в waf-lab.log, затем удаляет контейнеры своего проекта. Никаких результатов PASS в архив заранее не вложено.

CRS проверяйте отдельно от контрольного правила

На этом же изолированном стенде можно отправить тестовую строку XSS в поисковом параметре и посмотреть, какие правила CRS сработают:

curl -i --get 'http://127.0.0.1:18080/search' \
  --data-urlencode 'q=<script>alert(1)</script>'

Сопоставьте запрос с журналом, режимом и суммой аномальности. В DetectionOnly ожидается наблюдение, в On — блокировка при достижении порога. Одна такая проверка не доказывает защиту от всех XSS и других атак. Для настоящего приложения добавьте разрешённые бизнес-операции: вход, поиск, оформление заказа, JSON API и загрузку файлов.

Ложные срабатывания: исключать параметр, а не весь WAF

Если разрешённое действие блокируется, сохраните метод, путь, имя параметра, ID сработавшего правила и версию CRS. Повторите запрос на стенде. Правило итоговой блокировки по сумме баллов не обязательно является причиной: ищите правила, которые добавили эти баллы.

Допустим, проверка подтвердила ложное срабатывание правила 942100 на поле comment в POST /feedback. Тогда исключение должно относиться к этому полю и маршруту. Это условный пример: его нельзя включать без подтверждения причины и проверки безопасности поля в приложении.

SecRule REQUEST_URI "@streq /feedback" "id:100101,phase:1,pass,nolog,t:none,chain"
    SecRule REQUEST_METHOD "@streq POST" "t:none,ctl:ruleRemoveTargetById=942100;ARGS:comment"

Runtime-исключение загружается до CRS. В архиве оно сохранено как exclusion.example.conf и по умолчанию не подключено. Другие правила продолжают проверять запрос и тоже могут сработать. После изменения повторите разрешённую операцию и отрицательный тест на соседнем пути или в другом параметре. Механизмы исключений и порядок загрузки в CRS.

Не редактируйте поставляемые файлы правил: обновление затрёт правку. Не удаляйте всю категорию SQLi/XSS ради одного поля. У каждого исключения должны быть причина, ответственный и дата повторной проверки.

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

MODSEC_RULE_ENGINE=DetectionOnly docker compose -f compose.json up -d --force-recreate waf
curl -i 'http://127.0.0.1:18080/?secradar_waf_test=1'
docker compose -f compose.json down

Первое действие снимает блокирующие действия ModSecurity, но сохраняет его проверки. Последнее останавливает весь учебный проект. Это разные операции: в рабочей схеме остановка единственного reverse proxy делает приложение недоступным, если не предусмотрен другой маршрут.

Перед изменением рабочей политики сохраняйте конфигурацию, исключения, версии и digest. Возврат в DetectionOnly — временная мера, а не полный откат всех изменений. На стенде пересоздание контейнера допустимо; для рабочего сервиса заранее определите способ обновления без незапланированного простоя.

Что добавить перед эксплуатацией

TLS и реальный IP

В стенде опубликован только HTTP. Для HTTPS определите точку расшифровки, сертификаты и защищённый участок до backend. Если backend использует TLS, проверьте его сертификат и доверенный CA.

При наличии CDN или балансировщика доверяйте forwarded-заголовкам только от известных прокси. Не задавайте весь интернет как доверенную сеть. Сверьте клиентский IP в NGINX, журнале WAF и приложении. Модуль realip NGINX.

Ограничения и отказ

Проверьте размеры тела, длительные запросы, загрузки, WebSocket и потоковые ответы. Успешный HTTP handshake не подтверждает проверку последующих WebSocket-сообщений.

Зафиксируйте поведение при остановке WAF и потере backend, резервирование, доступность журналов и порядок восстановления. Учебный стенд эти свойства не подтверждает.

Журналы могут содержать параметры запросов и секреты. Используйте на стенде вымышленные данные, а в эксплуатации задайте состав журналирования, доступ и срок хранения. Проверка JSON движком не означает проверку OpenAPI-схемы, авторизации пользователя или прав на конкретный объект.

Обновления сервера, движка, коннектора и CRS проверяйте вместе с собственными исключениями. Успешная команда nginx -t подтверждает загрузку конфигурации, но не заменяет HTTP-проверки приложения и обработку ложных срабатываний.

Когда нужен готовый WAF-продукт

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

Сравнить документированные возможности российских WAF →

Разобраться в типах WAF и выбрать схему размещения →

Материал описывает учебную конфигурацию и критерии проверки. Он не является испытанием продуктов из сравнения. Источники и метаданные образов проверены 2 октября 2026 года. Как мы проверяем материалы →