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 — движок, который:
- разворачивает HTTP-запрос (и тело) в набор переменных (
ARGS,REQUEST_HEADERS,REQUEST_URI,REMOTE_ADDRи т.д.) и transformation-цепочки (URL-decode, lower-case, HTML-entity decode, base64…); - прогоняет по ним правила (
SecRule), каждое из которых при совпадении даёт действие: логировать, отдать 403, снять цель проверки, остановить цепочку; - пишет детали в 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). Если пакеты есть в вашем дистрибутиве — это путь по умолчанию: не надо руками пересобирать.
# ориентировочно (имена пакетов сверьте в своём дистрибутиве!)
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):
# 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-modulevs--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. Проверка, что всё встало
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:
# актуальный релиз 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. Внедрение без простреленной ноги
Порядок, который спасает нервы (и сайт):
- Неделя DetectionOnly на проде.
SecRuleEngine DetectionOnly. Ничего не блокируется, только пишется в audit-log. Пользователи не замечают WAF вообще. - Разбор лога.
modsec_audit.logразрастётся. Группируем срабатывания поidправила и URI (grep 'id'/утилита вродеa2ms2/modsec-rules-парсеры/просто jq если включён JSON-формат). Ищем систематические false positive: админка, REST,admin-ajax.php, загрузка медиа, формы с HTML в тексте. - Исключения, а не глушение. Для подтверждённых FP — точечные
SecRuleUpdateActionByTag/SecRuleRemoveById/ctl:ruleRemoveTargetById— и пишем их в900-EXCLUSION-RULES-BEFORE-CRS, с комментарием «почему». Не отключаем всю группу правил ради одного места. - Включаем On на подмножестве. Сначала
Onдля путей без тонкой настройки (публичные страницы, API без нестандартных форм), админку держим в DetectionOnly/с исключениями дольше. - Мониторим 403. После включения — алерт на всплеск 403 (WAF начал есть легитимный трафик = вернутся к исключениям). Регресс после каждого обновления CRS.
12. Как читать audit log
Секции записи (--...-- разделители): A — заголовок, B — тело запроса, … F — заголовок ответа, G — тело ответа, H — итог правил. Разбор в первую очередь по полю id: (номер правила), msg: (описание) и URI. Типовой grep:
# все срабатывания по 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 | Типовое ложное срабатывание | Куда применять исключение |
|---|---|---|
941xxx | XSS-детекторы на HTML в тексте поста | ARGS:content/post_content на post.php, admin-ajax.php, REST |
942xxx | SQLi-детекторы на запросы плагина к БД/фильтры | ARGS:search/s, иногда ARGS: на REST-фильтрах |
932xxx | RCE-детекторы на плагинах с shell-именами | точечно к пути конкретного плагина |
944xxx | загрузка файлов/MULTIPART | async-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» можно по живому анализу, а не по памяти. Попробуйте инструмент прямо здесь, на своих данных:
ИИ найдёт уязвимости и предложит исправления.
Источники
- OWASP ModSecurity — движок v3.0.17, github.com/owasp-modsecurity/ModSecurity
- Модуль nginx — github.com/owasp-modsecurity/ModSecurity-nginx (v1.0.4)
- OWASP Core Rule Set v4.30.0 — github.com/coreruleset/coreruleset, coreruleset.org
- Coraza v3.8.1 — github.com/corazawaf/coraza
- Справочник директив Seclang — GitHub owasp-modsecurity/ModSecurity · Reference
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
