29 июн. 2025 г.·7 мин

Замена коммерческого WAF на Nginx ModSecurity: атаки, FP, релизы

Замена коммерческого WAF на Nginx ModSecurity: какие атаки реально закрываются, как разбирать ложные срабатывания и встроить правила в релизы без простоев.

Замена коммерческого WAF на Nginx ModSecurity: атаки, FP, релизы

С чего начинается замена WAF и какие цели ставить

Переход с коммерческого WAF на связку Nginx + ModSecurity почти всегда начинается не с правил, а с причин. Обычно это стоимость лицензий, зависимость от вендора, желание полного контроля над настройками и журналами, а также требования к локальной поддержке и прозрачности цепочки поставок. Если эти причины не зафиксировать заранее, проект быстро превращается в бесконечную настройку «чтобы было как раньше», но без понимания, каким должен быть результат.

Ожидания лучше приземлить сразу. WAF снижает риск и отсекает часть атак, но не исправляет уязвимости в коде и не заменяет безопасную разработку. Если в приложении есть SQL-инъекция или небезопасная логика авторизации, фильтр может временно прикрыть симптомы, но проблема останется.

Дальше стоит проверить, подходит ли сервис для такого перехода. Самый удачный случай - веб-приложение с предсказуемыми URL и формами, понятными параметрами, стабильными клиентами и хорошими логами. Сложнее, когда много нестандартных API, частые релизы, разные команды, и любое лишнее срабатывание бьет по выручке. В таких системах иногда разумнее оставить managed WAF на периметре, а ModSecurity использовать как дополнительный слой или включать его только на отдельных доменах.

Перед стартом согласуйте вещи, которые потом экономят недели: кто владелец сервиса и кто владелец правил (кто принимает решение «блокируем»), SLA по инцидентам и по ложным блокировкам, окно изменений и способ отката, критерии успеха (например, доля перекрытых атак и допустимый процент ложных срабатываний), а также стартовый режим - только детект или сразу блокировка.

Когда цели и границы понятны, замена WAF перестает быть «магией безопасности» и превращается в управляемое инженерное изменение.

Что дают Nginx и ModSecurity на практике

В этой модели Nginx чаще всего работает как reverse proxy перед приложением. Он принимает входящий HTTP(S)-трафик, может завершать TLS, нормализовать запросы и уже затем отправляет их в upstream. Фильтрация включается на уровне Nginx (в контексте http/server/location) через подключение модуля ModSecurity, поэтому точка контроля оказывается перед приложением, там же, где обычно стоит и коммерческий WAF.

ModSecurity - это движок правил. Практически важно, что у него есть два основных режима:

  • Detection (фиксируем и логируем)
  • Blocking (блокируем)

В реальных внедрениях почти всегда начинают с Detection, чтобы увидеть, что именно будет ломаться, и только потом аккуратно включают блокировку.

Базовый старт дает OWASP CRS - набор типовых правил «из коробки», который закрывает большую часть массовых атак на веб-уровне (инъекции, подозрительные заголовки, обходы кодировок, необычные параметры). CRS не делает сервис «непробиваемым», но дает понятный минимум, с которым можно жить и постепенно улучшать.

Разница с коммерческими платформами часто проявляется в том, чего здесь нет по умолчанию: поведенческого анализа и автообучения под ваш трафик, продвинутой защиты от ботов (браузерные проверки, отпечатки, репутации), L7 DDoS-механик уровня managed-сервисов (челленджи, глобальные сети, готовые профили). Nginx + ModSecurity хорошо работают как прозрачный, контролируемый слой правил, но «автоматику» коммерческих WAF нужно либо компенсировать отдельными решениями, либо принимать как осознанный риск.

Какие атаки обычно перекрываются правилами

При подключении OWASP CRS первые выигрыши обычно видны на типовых веб-атаках. Это не «умная защита сама по себе», а сигнатуры и проверки того, что пришло в URL, заголовках, параметрах, JSON- или form-теле.

Самая частая категория - инъекции. Правила ловят характерные фрагменты для SQLi, XSS и командных инъекций: неожиданные кавычки и операторы, подозрительные функции, попытки закрыть контекст и добавить свой код. Например, запрос поиска с параметром вроде q=' OR 1=1 -- почти всегда поднимет тревогу, даже если приложение потом само защитится.

Вторая большая группа - попытки прочитать или обойти пути к файлам. Path traversal обычно выглядит как ../ (в разных кодировках) или как попытки открыть системные файлы. CRS хорошо отрабатывает и такие запросы, и сканерные обращения к типовым файлам и каталогам.

Отдельный пласт - нарушения протокола и «странные» запросы: некорректные методы, неожиданно большие тела, конфликтующие заголовки, подозрительные значения Content-Type, а также «ломаные» запросы, которыми часто пользуются боты и сканеры.

Часто срабатывают и правила по сессиям и cookie: слишком длинные значения, необычные наборы символов, попытки подсунуть код в cookie или заголовок. Это полезно против примитивных атак и шумного трафика.

Защиту админок лучше строить не только на CRS. Обычно помогает сочетание простых Nginx-контролей и точечных ограничений: разрешать только нужные методы, ограничивать доступ к служебным панелям по спискам IP, включать гео-ограничения только там, где это действительно оправдано.

Чем «шире» правила, тем выше риск ложных срабатываний на легитимных запросах. Поэтому начинать стоит с режима наблюдения и постепенно включать блокировку по самым уверенным категориям.

Границы защиты: что WAF не решает

При миграции на Nginx + ModSecurity важно заранее договориться о границах. WAF хорошо ловит типовые веб-атаки по правилам, но не делает приложение безопасным само по себе. Если ожидания завышены, вы получите либо «дыры», либо бесконечные ложные блокировки.

Где сигнатуры дают сбой

Правила уровня OWASP CRS во многом опираются на шаблоны. Их обходят вариациями полезной нагрузки, кодировками, разбиением параметров, редкими заголовками и нестандартным порядком полей. Иногда атака выглядит как обычный бизнес-запрос, и WAF не отличит ее без контекста приложения.

Отдельная ловушка - ожидание функций, которые часто приписывают WAF, но на практике это другие классы защиты: антибот и поведенческая защита (скрейпинг, накрутка, подбор), отпечатки устройств и риск-скоринг с сессиями, защита учетных записей (credential stuffing) на основе репутации, продвинутая защита API по схемам и контрактам, а также «управление инцидентами как сервис» (аналитики и реагирование).

Протоколы и производительность

Инспекция трафика зависит от того, как вы проксируете соединение. На TLS вы либо завершаете шифрование на прокси, либо не видите содержимое. С HTTP/2, WebSocket и особенно gRPC встречаются нюансы: долгоживущие соединения, бинарные тела, специфические заголовки. Формально это может работать, но разбор контента и правила становятся сложнее, а иногда и менее полезными.

По производительности проблемы чаще всего связаны с размером тел запросов и сложностью правил. Большие JSON, загрузки файлов, параллельные запросы и тяжелые регулярные выражения быстро съедают CPU. Если включить глубокую проверку везде, можно получить задержки и таймауты, которые будут выглядеть как сбой приложения.

Когда лучше комбинировать

WAF дает максимальный эффект, когда дополняет, а не заменяет остальные меры: исправления в коде для логических уязвимостей и авторизации, rate limiting и лимиты на размер тела, строгие контракты API (allowlist/схемы) для критичных эндпоинтов, отдельные антибот-решения там, где это действительно нужно бизнесу.

Если так подойти к границам защиты, ModSecurity станет предсказуемым слоем контроля, а не единственной линией обороны.

Выбор архитектуры и места в трафике

Первое решение - где будет стоять WAF. Самый простой вариант - на периметре, перед балансировщиком или сразу за ним, чтобы закрывать общий входной трафик. Это удобно, когда много сервисов и нужен единый контроль. Если сервисы очень разные (например, публичный сайт и внутреннее API), часто лучше ставить WAF ближе к конкретному сервису: так проще настроить правила и ниже риск сломать легитимные запросы.

Иногда WAF размещают в отдельной зоне (DMZ) как самостоятельный прокси-слой. Это полезно, когда важны строгие сетевые границы, но добавляет лишний хоп и усложняет отладку.

С отказоустойчивостью лучше не усложнять: WAF должен быть таким же надежным, как входная точка. Обычно выбирают актив-актив за балансировщиком (две и более ноды с одинаковой конфигурацией), актив-пассив (резервная нода и быстрое переключение) или горизонтальное масштабирование по нагрузке.

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

Храните конфиги как код: единый репозиторий, версионирование, ревью и понятные изменения. Тогда видно, почему появилось исключение и кто его добавил.

План отката должен быть быстрым: держите переключатель режимов (Detection/Off) на уровне сервиса или location. Если после релиза API выросло число блокировок, вы быстро переводите проблемное правило в Detection, фиксируете ложные срабатывания и возвращаете блокировку без остановки трафика.

Пошаговая миграция без остановки сервиса

Архитектура и отказоустойчивость WAF
Спроектируем размещение WAF в периметре, DMZ или ближе к сервисам под вашу схему.
Обсудить проект

Миграция WAF опасна не самой установкой, а резким переходом в режим блокировки. Чтобы пройти это без простоев, начинайте с наблюдения.

Сначала включите ModSecurity в режиме Detection (только логирование) и дайте ему поработать на реальном трафике. За 3-7 дней обычно видно базовую картину: какие правила срабатывают чаще всего, какие методы и URI попадают под проверки, где есть неожиданные пики.

Дальше подключайте OWASP CRS и тоже не спешите блокировать. На этом этапе важно проверить, как приложение ведет себя с типовыми проверками: формы, авторизация, поиск, загрузка файлов, API.

Параллельно приведите в порядок технические настройки, иначе часть запросов будет анализироваться неправильно. Чаще всего требуют внимания лимиты размера тела запроса и отдельных параметров, корректная обработка загрузок файлов (multipart) и типовых расширений, разбор JSON (content-type, кодировка), единый формат логов и корреляция с request id.

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

Заранее подготовьте короткий runbook для дежурных и владельцев приложения: как отличить атаку от ложного срабатывания, где искать событие в логах Nginx и ModSecurity, как временно ослабить правило точечно (по URI или параметру) и как откатить изменения без перезапуска всего сервиса.

Как собирать и разбирать ложные срабатывания

Ложное срабатывание (false positive) - это когда WAF блокирует или отмечает нормальный запрос реального пользователя или сервиса. Важно заранее договориться, кто принимает решение: безопасность отвечает за риск, а владелец приложения - за то, что запрос действительно легитимный и нужен бизнесу.

Начните с режима Detection и соберите базовую статистику. Без тихого периода вы почти наверняка будете тушить инциденты вместо настройки.

Чтобы разбирать события быстро, в логах полезно вытаскивать: идентификатор правила (rule id), что именно совпало (matched data), URL и метод, параметры и заголовки, статус ответа. По одному rule id часто видно, относится ли срабатывание к SQLi, XSS или, например, к подозрительному формату тела запроса.

Типовые способы подавления FP - от более безопасного к более рискованному:

  • узкое исключение по параметру (разрешить спецсимволы только в поле comment)
  • исключение по эндпоинту (только для конкретного URL с необычным форматом)
  • отключение правила по rule id (только при веской причине и с компенсацией другими мерами)

Исключения должны быть минимальными и объясненными. Добавляйте комментарий, владельца и срок действия (например, 30 дней), после которого исключение пересматривается. Если нужно ослабить проверку, сначала ограничьте ее для конкретного поля или формата, а не для всего сайта.

Хороший процесс работы с FP обычно выглядит так: тикет с примером запроса и временем, воспроизведение в тесте и подтверждение владельцем приложения, решение по исключению и согласование с безопасностью, внедрение правила вместе с релизом и короткая проверка логов после выката.

Встраивание правил в процесс релизов

Встраивание WAF в CI CD
Поможем выстроить процесс правил как код и выпускать изменения вместе с релизами.
Получить предложение

Самое важное здесь - перестать править правила вручную на проде. Правила должны жить рядом с кодом и выпускаться так же предсказуемо, как обычные изменения.

Правила как код

Удобно разделить базовые правила, исключения и локальные доработки. Тогда быстрее видно, что именно меняется, и проще откатывать:

  • crs/ - неизменяемый набор OWASP CRS (обновляется отдельными PR)
  • custom/ - ваши правила под конкретные приложения и API
  • exclusions/ - исключения (целевые, с привязкой к URL, параметру, методу)
  • tests/ - набор запросов для проверки (легитимных и атакующих)
  • docs/ - краткое описание соглашений и типовых решений

Для PR полезен короткий шаблон: зачем изменение, какой риск, какие эндпоинты затрагивает, какие логи и события ожидаются. Ревью обязательно: правило легко «починить» ложное срабатывание так, что вы случайно откроете дыру.

Как выпускать изменения

Разная строгость по средам - нормальная практика. На dev можно включать более агрессивные правила, чтобы рано ловить проблемы, а на prod держать минимально достаточную блокировку.

Перед релизом запускайте автотесты: «хорошие» запросы не должны блокироваться, а «плохие» должны стабильно ловиться. Рабочий порядок обычно такой: сначала Detection-only на stage, потом на небольшой доле prod, затем точечная блокировка по самым уверенным правилам, измерение эффекта (доля блоков, число FP, нагрузка, жалобы пользователей), быстрый откат (флаг/переменная окружения или возврат на прошлый тег правил).

Так вы выпускаете правила маленькими порциями, видите эффект сразу и не превращаете WAF в «черный ящик», который мешает релизам.

Наблюдаемость: логи, метрики и алерты

При переходе на Nginx + ModSecurity вы теряете часть «готовых» дашбордов, поэтому наблюдаемость нужно собрать осознанно. Иначе вы либо не заметите атаку, либо начнете отключать правила наугад из-за ложных срабатываний.

Полезный минимум, который стоит смотреть регулярно: доля блокировок (blocked vs allowed) по часам и дням, топ срабатывающих правил (rule id) и их динамика, топ эндпоинтов с срабатываниями, задержка на уровне Nginx и влияние WAF (если измеряете отдельно), распределение статус-кодов (200/3xx/4xx/5xx) рядом с WAF-событиями.

Важно не смотреть WAF отдельно от приложения. Если после правки правил выросли 403, проверьте, какие запросы стали блокироваться и совпадает ли это с ростом ошибок в приложении. Если выросли 5xx, это может быть не атака, а побочный эффект: правило пропустило «тяжелый» запрос и приложение не выдержало, или наоборот, из-за ретраев и таймаутов выросла нагрузка.

Алерты лучше делать простыми: резкий всплеск блокировок относительно среднего (например, в 3-5 раз), рост 403 по одному эндпоинту или у одного клиента/подсети, рост 5xx сразу после изменения правил или обновления OWASP CRS, появление нового правила в топе, устойчивый рост latency на входе после включения блокировки.

Логи храните так, чтобы можно было разбирать инциденты и FP: запрос, правило, причина, endpoint, идентификатор корреляции (request id), источник. Раз в 2-4 недели пересматривайте исключения: старые пути приложения уходят, новые появляются, а временные обходы часто остаются «навсегда» и превращаются в дыры.

Частые ошибки при замене коммерческого WAF

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

Ошибки, которые больнее всего бьют по доступности

Чаще всего это выглядит так: сразу включают блокировку без тихого периода и получают неожиданные 403 на легитимные запросы; делают исключения слишком широкими (например, «не проверять весь /api»), а потом забывают; не проверяют реальные форматы трафика (JSON, multipart, большие файлы, длинные заголовки, нестандартные кодировки); живут без плана отката и без ответственного человека; путают WAF и защиту от всплесков (WAF ловит классы атак на уровне запросов, но не заменяет rate limiting и базовую защиту от перегрузки).

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

Короткий пример из практики

У команды есть портал с формой загрузки документов и отдельный JSON API для мобильного приложения. После включения правил начинают «сыпаться» события на параметр comment, потому что пользователи вставляют текст с символами \u003c\u003e или фрагментами кода. Если просто отключить проверку целиком для всех POST-запросов, вы потеряете защиту там, где она нужна.

Правильнее сузить исключение: привязать его к конкретному параметру и конкретному эндпоинту, оставить срок пересмотра и параллельно добавить rate limiting на самые дорогие методы (например, загрузки).

Короткий чеклист перед и после включения блокировки

Интеграция WAF в общую защиту
Соберем инфраструктуру вокруг WAF: прокси, балансировка, лимиты, контроль доступа и откаты.
Запросить решение

Самый рискованный момент - перевод из Detection в Blocking. Ниже чеклист, который помогает не «положить» легитимный трафик и не утонуть в разборе инцидентов.

Перед включением блокировки проверьте базу, чтобы OWASP CRS работал предсказуемо и логи были полезными:

  • Зафиксированы сервисы и критичные эндпоинты, владельцы, окна изменений.
  • Настроены лимиты размера тела запроса, разрешенные методы, кодировки, нормализация URL.
  • Включен real IP (чтобы в событиях был реальный клиент, а не балансировщик) и единый формат логов.
  • Старт выполнен в Detection и этапы включения запланированы: один сервис или небольшая доля трафика, затем расширение.
  • Есть процесс по ложным срабатываниям: кто принимает запрос, SLA на разбор, где хранится решение, как именуются исключения и когда их пересматривать.

После первого релиза в Blocking важно закрепить контроль:

  • Следить за метриками: доля блокировок, топ правил, топ URL, рост 4xx/5xx и влияние на ключевые бизнес-события.
  • Настроить алерты на всплески блокировок по одному эндпоинту, правилу и источнику.
  • Делать короткое ретро по каждому инциденту: что заблокировали, почему, как обнаружили, что улучшить в правилах и тестах.
  • Регулярно чистить исключения: удалять временные, объединять дубли, фиксировать срок действия и владельца.
  • Сверять изменения с релизами приложения: если обновился API или добавилась новая форма, заранее готовить корректировки правил и тест-кейсы.

Пример реального внедрения: от пилота до стабильной защиты

Представим компанию с двумя точками входа: внутренний портал для сотрудников (вход по VPN, много админских действий) и внешняя форма для клиентов (публичный трафик, важна конверсия). В процессе миграции быстро становится видно, что риски разные: для портала важнее жестко блокировать вредные запросы к админке, а для формы - не сломать легитимные отправки.

Пилот удобно разложить по неделям:

  • Неделя 1: режим Detection. Собирают события по OWASP CRS, выделяют топ-10 правил и топ-20 URL, где больше всего срабатываний, и отмечают, где это похоже на атаки, а где упирается в бизнес-логику.
  • Неделя 2: точечные исключения. Делают узкие exclusions только для конкретных параметров и путей, прогоняют на stage типовые сценарии (логин, поиск, отправка формы). Для админки включают частичный Blocking по самым понятным классам (SQLi, RCE, попытки обхода авторизации).
  • Неделя 3: расширение Blocking. Постепенно добавляют блокировку на внешнюю форму, но начинают с редких и явно вредных сигнатур и с аномальных запросов, которые не встречаются в нормальном трафике.

Чтобы понять, не вредите ли вы продукту, заранее договариваются, что смотрят каждый день: конверсию внешней формы и долю ошибок 4xx/5xx, время ответа и рост ретраев со стороны клиентов, долю заблокированных запросов по ключевым URL, число обращений в поддержку с симптомом «не отправляется» или «не пускает».

Дальше обычно всплывают архитектурные вопросы: где теряются реальные IP, как разделить политики для портала и формы, как версионировать правила вместе с релизами. Если не хватает рук или нужна поддержка 24/7, этот этап часто передают интегратору. Например, GSE.kz (gse.kz) как системный интегратор может помочь с внедрением и сопровождением инфраструктуры вокруг WAF в составе общей системы защиты.

Замена коммерческого WAF на Nginx ModSecurity: атаки, FP, релизы | GSE