WAF и ModSecurity: установка, настройка, правила

Web Application Firewall — слой, который перехватывает HTTP-трафик до приложения и отсекает типовые атаки по сигнатурам: инъекции, XSS, сканеры, загрузка шеллов. Это полезная часть defense-in-depth, но с двумя большими оговорками, которые забывают новички: WAF не заменяет безопасный код (параметризацию и экранирование см. в статьях про SQL-инъекции и XSS/CSRF), и включённый «на полную» без притирки WAF ломает сайт — режет админку, REST, загрузку медиа. Ниже — как поставить, настроить и, главное, как внедрять без боли.

Стек примеров — типичный LEMP/VPS на Ubuntu/Debian с Nginx + PHP-FPM. Дано на актуальных версиях по состоянию на октябрь 2026; версии помечены явно, чтобы вы сверились при чтении.


Часть I. Что такое WAF и чем он не является

1. Классы WAF по месту в трафике

  • Сетевой / inline — стоит «в потоке» между клиентом и сервером, может блокировать на уровне пакетов/HTTP.
  • Reverse-proxy (хостовый) — работает на вашем же веб-сервере или на прокси перед ним: ModSecurity+nginx, Coraza, HAProxy с Lua. Трафик заходит на ваш сервер уже проверенным.
  • Облачный / CDN — Cloudflare, AWS WAF, Akamai и т.п.: фильтрация до того, как запрос дотронется до origin. Плюс — не жрёт ваши CPU/RAM и не падает вместе с вами; минус — меньше контроля, «чёрный ящик», оплата.

Практический выбор для самохостимого VPS: облачный WAF/CDN снимает DDoS и типовые боты до сервера (rate limit от DDoS не спасает, это задача CDN/WAF на сети), а хостовый ModSecurity/Coraza даёт вам контроль над правилами под конкретное приложение. Эти два уровня не конфликтуют — они складываются вместе.

2. Честный лимит возможностей

WAF на сигнатурах ловит то, что похоже на известные атаки. Он слеп к тому, чего не знает:

  • 0-day и обфускация. New payload / хитрое кодирование могут проскочить (поэтому CRS — живой проект, патчащий обходы регулярно; релиз v4.30.0 как раз закрыл несколько обходов правил RCE и charset-фильтра).
  • Логика приложения. IDOR, пропуск шага оплаты, «купон дважды» (см. статью про аудит) WAF не видит в принципе — он не знает, чей это заказ.
  • Зашифрованный трафик без терминали. Если WAF не стоит на месте, где трафик расшифрован, он ничего не увидит.

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

3. Как работает движок ModSecurity

ModSecurity — движок, который:

  1. разворачивает HTTP-запрос (и тело) в набор переменных (ARGS, REQUEST_HEADERS, REQUEST_URI, REMOTE_ADDR и т.д.) и transformation-цепочки (URL-decode, lower-case, HTML-entity decode, base64…);
  2. прогоняет по ним правила (SecRule), каждое из которых при совпадении даёт действие: логировать, отдать 403, снять цель проверки, остановить цепочку;
  3. пишет детали в audit log (это главный инструмент тюнинга).

Правила — не «через модуль сервера», а декларативно в конфигах формата, общего для всех коннекторов (Seclang). Один и тот же CRS крутится на nginx, Apache, Coraza — в этом смысл.


Часть II. Архитектура и варианты установки

4. Три «лица» ModSecurity — не путайте их

ЧтоЭтоКогда брать
libmodsecurity v3 (движок, 3.0.17)C++ библиотека libmodsecurity.soсам по себе ничего не делает — нужен коннектор
ModSecurity-nginx v1.0.4динамический модуль nginx, мост к libmodsecurity v3основной путь на Nginx/LEMP
mod_security2 (Apache)Apache-модуль на движке v2 (не v3!)если у вас Apache, а не nginx

Критично: у Nginx нет встроенного ModSecurity. Его надо прикручивать снаружи — либо dynamic module ModSecurity-nginx (рекомендуемый путь, сервер пересобирать не обязательно), либо статически пересобрать nginx с модулем. Формулировка «встроенный модуль nginx с OWASP» — ошибка, с которой я вас однажды правил в заметках: nginx требует сторонний коннектор (libmodsecurity + ModSecurity-nginx).

Для Apache исторически работает mod_security2 (ветка v2, 2.9.x) — это отдельный код, не v3. Движок v3 к Apache официально не портирован так же гладко; на практике, если стек nginx — ставьте v3+connector, если Apache — v2+CRS тоже работают (CRS поддерживает обе ветки).

5. Coraza — современная альтернатива на Go

Coraza v3.8.1 (октябрь 2026) — реализация того же языка правил Seclang на Go, совместимая с CRS. Развитие движка ModSecurity v3 за последние годы заметно замедлилось, и сообщество частично мигрирует на Coraza, которая:

  • легко встраивается в Caddy (плагин caddy-security/coraza), Envoy (coraza-proxy-wasm), Go-приложения;
  • свежая security-ветка (v3.8.0/v3.8.1 закрыли несколько crash/memory-exhaustion CVE в JSON и multipart body-процессорах — см. релиз);
  • вносит полезные лимиты по умолчанию (SecArgumentsLimit 1000), закрывающие «съедание памяти» на раздутых телах.

Для WordPress+nginx из примеров ниже — основной путь ModSecurity v3. Но Coraza — честная рекомендация, если не хотите возиться со сборкой C-модуля под nginx: у Caddy/Coraza всё собирается как обычный Go-плагин.


Часть III. Установка на Nginx (LEMP)

6. Путь А — готовые пакеты (Ubuntu/Debian)

Самый простой способ — собрать nginx с модулем из репозитория сообщества и поставить библиотеку. На Debian/Ubuntu движок и модуль обычно доступны как .deb (имена пакетов зависят от релиза и репо — проверьте apt search modsecurity; популярный источник — PPA Oondro/nginx с включённым http-headers-more/modsecurity). Если пакеты есть в вашем дистрибутиве — это путь по умолчанию: не надо руками пересобирать.

Bash
# ориентировочно (имена пакетов сверьте в своём дистрибутиве!)
sudo apt update
sudo apt install libmodsecurity3 libapache2-mod-security2  # библиотека (+ apache-модуль, если он есть)
sudo apt install nginx-extras   # или отдельный nginx-module-modsecurity из стороннего репо

7. Путь Б — сборка движка v3 + dynamic module nginx

Когда пакетов нет/нужна конкретная версия (например актуальный v3.0.17):

Bash
# 1) зависимости сборки
sudo apt install -y git autoconf libtool make pkg-config \
  libcurl4-openssl-dev libyajl-dev libssl-dev libpcre2-dev \
  libgeoip-dev liblmdb-dev libmaxminddb-dev bison flex

# 2) движок libmodsecurity v3 (репозиторий переехал на owasp-modsecurity)
git clone -b v3/master --recursive \
  https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
./build.sh && ./configure && make -j"$(nproc)" && sudo make install
# итог: /usr/local/lib/libmodsecurity.so, конфиг в /usr/local/etc/modsecurity/

# 3) коннектор nginx (v1.0.4) собирается как dynamic module
# ВАЖНО: версия заголовков nginx = версия вашего nginx (nginx -v)
git clone https://github.com/owasp-modsecurity/ModSecurity-nginx.git
# скачиваем исходники вашего nginx той же версии
NGX_VER=$(nginx -v 2>&1 | sed 's|.*/||')
curl -O "https://nginx.org/download/nginx-${NGX_VER}.tar.gz"
tar xf "nginx-${NGX_VER}.tar.gz"

# 4) компилируем только модуль (--with-ld-opt обязателен для линковки)
cd ModSecurity-nginx
./configure --with-ld-opt="-Wl,-rpath,/usr/local/lib" \
  --add-module=/usr/local/ModSecurity-nginx \
  --with-openssl=/usr/include/openssl  # если нужен
make -j"$(nproc)"
# готовый модуль: objs/ngx_http_modsecurity_module.so
sudo install -m755 objs/ngx_http_modsecurity_module.so \
  /usr/share/nginx/modules/ngx_http_modsecurity_module.so

--add-dynamic-module vs --add-module: чтобы не пересобирать весь nginx, обычно собирают модуль динамическим (--with-cc-opt+--add-dynamic-module= на исходниках nginx), кладут .so в modules/ и грузят строкой load_module в nginx.conf. Приведённая выше схема — сжатый вариант; канонический рецепт — в README ModSecurity-nginx.

8. Подключение модуля и базовый конфиг nginx

# /etc/nginx/nginx.conf (верх main-блока)
load_module modules/ngx_http_modsecurity_module.so;

http {
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

    server {
        listen 443 ssl;
        server_name shop.example.com;

        # ... остальное
    }
}

Файл /etc/nginx/modsecurity/modsecurity.conf обычно собирают из рекомендованного modsecurity-config-recommended.conf (идёт в исходниках движка) и дальше подключают CRS (см. Часть IV).

Для Apache: a2enmod security2, конфиг в modsecurity_crs_10_config.conf/crs-setup.conf, модуль грузит CRS автоматически из rules/ — путь проще, чем сборка на nginx.

9. Проверка, что всё встало

Bash
sudo nginx -t                                   # конфиг валиден, модуль загрузился
sudo systemctl restart nginx
# «атака», которую CRS должен отловить в DetectionOnly-логе:
curl -s 'https://shop.example.com/?p=%27%20OR%201=1--'
# ищем запись в audit/error
sudo grep -i 'modsecurity\|audit' /var/log/nginx/error.log

Часть IV. Правила: OWASP CRS

10. CRS — это то, что реально защищает

Сам движок без правил бесполезен — вы пишете пустой файл и ждёте. Промышленный стандарт правил — OWASP Core Rule Set (CRS), сейчас актуален v4.30.0 (октябрь 2026). Это сотни готовых SecRule, покрывающих SQLi, XSS, RCE, LFI/RFI, сканеры, аномалии протокола, загрузку файлов и т.д., в категориях по группам (REQUEST-901, 920 protocol, 930 app attack, 932 RCE, 940 XSS, 941 PHP, 942 SQLi, 950 disclosure…).

CRS патчится от обходов регулярно — релиз v4.30.0 закрыл, например, обход RCE-правил (932) через путь в REQUEST_FILENAME, и два обхода проверки charset через CHARSET= в разных регистрах. Отсюда важное: CRS — не «поставил и забыл», его надо обновлять так же, как вендорский софт.

Установка CRS:

Bash
# актуальный релиз 4.30.0 (сверьте версию на странице релизов)
CRSVER=4.30.0
curl -sL "https://github.com/coreruleset/coreruleset/releases/download/v${CRSVER}/coreruleset-${CRSVER}.tar.gz" \
  -o crs.tar.gz
tar xf crs.tar.gz
sudo cp -r crs-${CRSVER}/crs /etc/nginx/modsecurity/crs
cd /etc/nginx/modsecurity/crs
sudo cp crs-setup.conf.example crs-setup.conf
sudo cp rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example \
         rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Подключение в modsecurity.conf:

# ... после SecRuleEngine/SecRequestBodyAccess/SecAuditEngine

# CRS: порядок важен — setup → правила исключений → сами rules
Include /etc/nginx/modsecurity/crs/crs-setup.conf
Include /etc/nginx/modsecurity/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Include /etc/nginx/modsecurity/crs/rules/*.conf

Порядок Include значим: 900-EXCLUSION-…BEFORE-CRS подключается до основных правил, чтобы снять ложные срабатывания заранее. Для Apache это те же файлы, путь под modsecurity_crs_10_config.conf/rules/.

11. Paranoia Level (PL) и anomaly score

CRS настраивается через SecAction с id в диапазоне 900xxx прямо в crs-setup.conf:

  • Paranoia Level (900270) — по умолчанию 1. Чем выше (до 4), тем агрессивнее правила: ловит больше атак, но и больше false positive. На реальном сайте с WP админкой начинают с PL1, повышают точечно и только если знают, зачем.
  • Anomaly score (default mode CRS 4) — CRS не обязательно отдаёт 403 на одно попадание; он копит «баллы» за входящие и исходящие аномалии и блокирует по порогу (900110/900111/900120/900130). Пороги (anomaly_inbound_high = 5, outbound = 4 — значения сверьте по вашей версии setup) влияют на то, насколько легко «набрать» блокировку.

Практика: держите PL1 + anomaly default, включите сначала логирование, соберите статистику, и уж потом поднимайте агрессивность.


Часть V. Настройка ключевых директив

Базовый набор директив движка (в modsecurity.conf), которые определяют поведение и цену:

# 1) Режим движка
SecRuleEngine DetectionOnly        # → On, когда притрёте (см. Часть VI)
SecRequestBodyAccess On            # читать тело запроса — почти всегда нужно
SecResponseBodyAccess Off          # читать тело ОТВЕТА — дорого, включайте точечно

# 2) Лимиты тела (иначе раздутый POST = память/CPU)
SecRequestBodyLimit 134217728      # 128 MB максимум (под ваш размер аплоада)
SecRequestBodyNoFilesLimit 131072  # 128 KB для обычных форм
SecRequestBodyLimitAction Reject   # Reject | ProcessPartial

# 3) Аудит-лог (главный инструмент тюнинга)
SecAuditEngine RelevantOnly        # RelevanceOnly | On | DynAlert
SecAuditLogRelevantStatus "^(?:5|4(?!04))"  # логировать 5xx и 4xx кроме 404
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/modsec_audit.log
SecAuditLogParts ABCFHZ

# 4) Временные файлы тела (если включён ProcessPartial/дисковый буфер)
SecTmpDir /tmp/modsec
SecDataDir /var/cache/modsecurity

# 5) Запрет на утечку версий/сервера
SecServerSignature "ModSecurity"

Что важно понимать:

  • DetectionOnly vs On — единственная директива, определяющая «смотрит или кусает». Всегда начинайте с DetectionOnly.
  • SecResponseBodyAccess — нужен, чтобы ловить утечки данных в ответе (disclosure-правила, кард-номера), но проверяет каждое тело ответа, что на большой выдаче ощутимо дороже. Включают точечно (по Content-Type, по путям).
  • SecRequestBodyLimitAction: Reject отбивает слишком большой запрос (защита от перегрузки, но ломает легитимный большой аплоад), ProcessPartial читает только лимитную часть и помечает флаг (тогда CRS-правило на REQUEST_BODY_LINE может не увидеть хвост). Для WP-загрузчика медиа поднимайте SecRequestBodyLimit под ваш реальный размер файлов.
  • SecAuditLogParts — что писать в секции аудита: A (заголовок запроса), B (тело запроса), F (заголовки ответа), G (тело ответа — включайте, если нужны disclosure-правила), H (последствия правил — нужно!). Секции C/D/E/Z опциональны. Минимум для тюнинга — ABCFHZ.

Coraza-эквиваленты близки, плюс у него SecArgumentsLimit по умолчанию 1000 и правила 200002–200009 в recommended-config (отбивают переполненные/битые JSON/multipart/URI). Если берёте Coraza — берите и его coraza.conf-recommended, иначе лимиты молча не сработают (об этом предупреждает сам релиз v3.8.1).


Часть VI. Внедрение без простреленной ноги

Порядок, который спасает нервы (и сайт):

  1. Неделя DetectionOnly на проде. SecRuleEngine DetectionOnly. Ничего не блокируется, только пишется в audit-log. Пользователи не замечают WAF вообще.
  2. Разбор лога. modsec_audit.log разрастётся. Группируем срабатывания по id правила и URI (grep 'id'/утилита вроде a2ms2/modsec-rules-парсеры/просто jq если включён JSON-формат). Ищем систематические false positive: админка, REST, admin-ajax.php, загрузка медиа, формы с HTML в тексте.
  3. Исключения, а не глушение. Для подтверждённых FP — точечные SecRuleUpdateActionByTag/SecRuleRemoveById/ctl:ruleRemoveTargetById — и пишем их в 900-EXCLUSION-RULES-BEFORE-CRS, с комментарием «почему». Не отключаем всю группу правил ради одного места.
  4. Включаем On на подмножестве. Сначала On для путей без тонкой настройки (публичные страницы, API без нестандартных форм), админку держим в DetectionOnly/с исключениями дольше.
  5. Мониторим 403. После включения — алерт на всплеск 403 (WAF начал есть легитимный трафик = вернутся к исключениям). Регресс после каждого обновления CRS.

12. Как читать audit log

Секции записи (--...-- разделители): A — заголовок, B — тело запроса, … F — заголовок ответа, G — тело ответа, H — итог правил. Разбор в первую очередь по полю id: (номер правила), msg: (описание) и URI. Типовой grep:

Bash
# все срабатывания по id за последние сутки, топ-15
sudo grep -oE 'id "[0-9]+"' /var/log/modsecurity/modsec_audit.log \
  | sort | uniq -c | sort -rn | head -15

# найти, какие URI чаще всего ловят SQLi-правило 942100
sudo awk '/id "942100"/{print}' /var/log/modsecurity/modsec_audit.log | head

Формат audit-лога переключают на JSON (SecAuditLogFormat JSON), тогда удобно jq‘ом группировать.

13. Исключения: как не развалить CRS

Три механизма (от грубого к тонкому):

  • SecRuleRemoveById 942100 — выключить правило целиком (глобально). Редко оправдано.
  • SecRuleRemoveByTag, SecRuleRemoveByMsg — по тегу/сообщению, но тоже глобально.
  • Точечно и контекстно (правильный способ): ctl:ruleRemoveTargetById=942100;ARGS:body — снять проверку конкретного аргумента для конкретного пути, через SecRuleUpdateTargetBy… или через правило-исключение по URI. Пример в Части VIII/WP.

Плюс 900xxx-параметры в crs-setup.conf и whitelist ip (SecRemoteRules, SecAction по REMOTE_ADDR для вашего мониторинга).


Часть VII. Свои правила

CRS покрывает типовое; своё правило пишут, когда нужна специфика приложения. Синтаксис SecRule:

# SecRule <переменные> <оператор> <паттерн> "action1,action2,..."
SecRule REQUEST_URI "@beginsWith /admin/" "id:100001,phase:1,pass,nolog,\
  ctl:ruleRemoveTargetById=941100;ARGS:content"

# Собственное правило «блок»: POST на /api/export только из whitelisted IP
SecRule REMOTE_ADDR "!@ipIn 198.51.100.0/24" "id:100002,phase:1,deny,status:403,\
  msg:'export не с разрешённого IP',tag:'app/export'"

Из чего строить:

  • переменные: REQUEST_URI, ARGS, ARGS_POST_NAMES, REQUEST_HEADERS:User-Agent, MULTIPART_FILENAME, REMOTE_ADDR, REQUEST_BODY и др.;
  • операторы: @rx (регулярка), @pm/@pmFromFile (набор слов — быстрее регулярок), @beginsWith, @streq, @contains, @detectSQLi/@detectXSS (готовые), @validateByte/@validateUrlEncoding;
  • transformations (t:none, t:lowercase, t:urlDecodeUni, t:htmlEntityDecode) — до проверки; не укажите нужные — payload обойдёт в кодировке;
  • phase: — 1 (заголовки запроса), 2 (тело), 3 (ответ), 4 (лог-ответа), 5 (афтермаркет);
  • chain: — несколько условий через SecRule … chain в одну цепочку;
  • id: — всегда уникален; не берите id из диапазона CRS, держите свой (1000xx+), иначе пересечётесь с обновлением.

Регулярки на SecRule исполняются на каждом запросе. Массовые тяжёлые @rx на REQUEST_URI в пике — это latency. Для наборов слов предпочитайте @pm/@pmFromFile; для точного соответствия — @streq, а не якоренную регулярку. И не допускайте катастрофического backtracking (ReDoS на уровне WAF), тестируя паттерны на длинных входных строках.

14. Производительность — где WAF дорого стоит

  • Чтение тела запроса (SecRequestBodyAccess On) всегда дороже, чем только заголовки; чтение тела ответа (SecResponseBodyAccess) — заметно дороже всего (каждый рендер).
  • Агрессивные PL/аномалии = больше правил на запрос.
  • Тяжёлые @rx и большие @pmFromFile — CPU на каждую строку.
  • Audit-log на RelevantOnly и с минимальным набором секций — иначе на 10k rps лог займёт диск за часы.

Мониторьте nginx -T-нагрузку, время отклика с WAF и без, и размер audit-лога. Если после включения выросла 502/504 — это WAF упёрся в CPU/лимиты тела, а не приложение.


Часть VIII. Специфика WordPress на Nginx + ModSecurity

WP генерит много легитимного «похожего на атаку» трафика. Без притирки CRS ложит:

  • Загрузка медиа/видео (multipart, большой POST). CRS-файловые правила (944xxx) могут резать по имени файла/MIME. Убедитесь, что SecRequestBodyLimit и SecRequestBodyNoFilesLimit покрывают ваши аплоады; при FP на конкретном хостинге формы — точечное исключение на admin-ajax/async-upload.php.
  • Тексты постов с HTML/JS (editor шлёт разметку в POST) — детекторы XSS (941xxx) и «запретных слов» иногда срабатывают на нормальный контент. Классика: исключения по content, post_content, excerpt для авторизованных путей.
  • REST /wp-json/ и admin-ajax.php — нетипичные формы, JSON-тело, ?rest_route=. CRS может не понять application/json, если не включён JSON body processor (SecRequestBodyAccess On + JSON support). На Coraza JSON уже обрабатывается (вот там и лимиты по JSON-вложенности, и SecArgumentsLimit из v3.8.x актуальны).
  • xmlrpc — отдельная мишень; в статье про аудит он закрыт с другой стороны (pingback-DRDoS, system.multicall); если не нужен — лучше выключить на уровне сервера, а не полагаться на WAF.

Типовые id, которые чаще всего ложат на WP-пути и куда вешают точечные исключения (значения по вашей версии CRS сверяйте по changelog — нумерация стабильна, но покрытие правил меняется):

Группа idТиповое ложное срабатываниеКуда применять исключение
941xxxXSS-детекторы на HTML в тексте постаARGS:content/post_content на post.php, admin-ajax.php, REST
942xxxSQLi-детекторы на запросы плагина к БД/фильтрыARGS:search/s, иногда ARGS: на REST-фильтрах
932xxxRCE-детекторы на плагинах с shell-именамиточечно к пути конкретного плагина
944xxxзагрузка файлов/MULTIPARTasync-upload.php, media-new.php, SecRequestBodyLimit под размер

Пример точечного исключения (WP admin-редактор):

# 900-EXCLUSION-RULES-BEFORE-CRS.conf
# Для авторизованных путей редактора разрешить HTML в content (это легитимный код редактора)
SecRule REQUEST_URI "@pm /wp-admin/post.php /wp-admin/admin-ajax.php" "id:100010,\
  phase:1,pass,nolog,ctl:ruleRemoveTargetById=941160;ARGS:content,\
  ctl:ruleRemoveTargetById=941100;ARGS:content,\
  ctl:ruleRemoveTargetById=941300;ARGS:content"

Не удаляйте правило по id глобально (SecRuleRemoveById 941100) ради редактора — вы вырубите детектор XSS для всего сайта. Снимайте конкретную цель (ruleRemoveTargetById) конкретным путём. Это принципиальная разница между «настроить» и «отключить защиту».

Обязательно закройте WP-специфику, не только через WAF: закрытие xmlrpc, ?author=, rate-limit на wp-login. WAF не заменяет это.


Часть IX. Чек-лист внедрения WAF

Подготовка

  • Решён уровень: облачный CDN/WAF + хостовый (ModSecurity/Coraza) — не одно вместо другого.
  • Понятно, что защищаем (Nginx/Apache/Caddy), и какой коннектор/модуль ставим.
  • Есть резерв диска под audit-лог и понимание, как его ротируют (`logrotate` — обязательно!).

Установка

  • Актуальная версия: движок `libmodsecurity v3` + `ModSecurity-nginx` (или `mod_security2` для Apache, или Coraza). Пакет/сборка задокументированы.
  • `nginx -t` проходит, модуль загружен (`load_module`).
  • CRS актуальной версии установлен, `crs-setup.conf` скопирован из example, подключение в правильном порядке (900→rules).

Настройка

  • `SecRuleEngine DetectionOnly` на первом этапе.
  • `SecRequestBodyAccess On`, лимиты тела под реальные аплоады.
  • `SecResponseBodyAccess` — по решению (дорого), не по умолчанию везде.
  • `SecAuditEngine RelevantOnly`, `SecAuditLogParts ABCFHZ`, аудит пишется и ротируется.
  • PL1, аномалии по default; aggressive-режимы не включались «на всякий».

Притирка

  • Прогон DetectionOnly 1–2 недели; топ-sрабатываний по id разобраны.
  • FP закрыты точечными исключениями (`ruleRemoveTargetById`) в `900-EXCLUSION`, не глобальным снятием.
  • WP-пути (редактор, загрузка, REST, admin-ajax) проверены на ложные срабатывания.

Включение и после

  • `SecRuleEngine On` (сначала на подмножестве, админка дольше в DetectionOnly).
  • Мониторинг всплеска 403 после включения (WAF ест легитим).
  • CRS включён в регулярные обновления (CVE/обходы патчатся); после обновления — регресс-проверка.
  • Понятна политика: что делать при обнаружении реальной эксплуатации (WAF-подтверждение атаки на приложение ≠ починка приложения).

Гигиена

  • Audit-лог не содержит секретов/паролей в открытом виде (тело запросов там — учтите, это чувствительные данные; ограничьте доступ к файлу).
  • WAF не единственный барьер: параметризация, экранирование, права БД, обновление плагинов — по статьям серии.

Инструмент под задачу

Проверить свои ModSecurity-директивы и .htaccess/nginx-обвязку WAF на «не разваливает ли CRS живой WordPress» можно по живому анализу, а не по памяти. Попробуйте инструмент прямо здесь, на своих данных:

AI Htaccess Analyzer
Гость
Токены: 0 / 50 000
Гостевой лимит — 50 000 токенов. Зарегистрируйтесь — для пользователей лимит + 200 000 токенов.
0 / 20 000 символов

Результат анализа
Вставьте .htaccess слева и нажмите «Анализировать».
ИИ найдёт уязвимости и предложит исправления.

Источники

👤 Зарегистрируйтесь, чтобы добавить материал в закладки.