Web Application Firewall (WAF) — это слой защиты, который анализирует HTTP-трафик и блокирует подозрительные запросы до того, как они достигнут вашего приложения. WAF защищает от SQL-инъекций, XSS, path traversal и многих других атак уровня приложения (L7).
Зачем нужен WAF
Классический firewall (iptables, security groups) работает на L3/L4 — он видит IP-адреса и порты, но не понимает содержимое HTTP-запросов. WAF работает на L7 — он анализирует URL, заголовки, параметры, тело запроса.
Что может WAF и не может обычный firewall:
- Блокировать SQL-инъекции — обнаружить "OR 1=1" в параметрах
- Остановить XSS — найти <script> в пользовательском вводе
- Защитить от path traversal — обнаружить "../../../etc/passwd"
- Rate limit по URL — разные лимиты для /api/ и /static/
- Блокировать плохих ботов — по User-Agent, поведению, fingerprint
- Виртуальный патчинг — заблокировать эксплуатацию известной уязвимости до выпуска патча
Типы WAF
Cloud WAF — Cloudflare, AWS WAF, Akamai, Imperva. Работают как reverse proxy, трафик идёт через них. Легко настроить, автоматически обновляются, но есть latency и стоимость.
Self-hosted WAF — ModSecurity, NAXSI, Coraza. Устанавливаются на ваш сервер как модуль nginx/Apache. Полный контроль, нет дополнительной latency, но требуют настройки и обновления.
Многие комбинируют оба подхода: Cloud WAF на edge для первичной фильтрации + self-hosted WAF для глубокой инспекции.
OWASP Core Rule Set (CRS)
OWASP Core Rule Set — это open-source набор правил для WAF, который защищает от наиболее распространённых атак. Он используется в ModSecurity, Coraza и поддерживается многими Cloud WAF.
Категории правил CRS
- SQL Injection (SQLi) — обнаружение попыток SQL-инъекций в параметрах, заголовках, cookies
- Cross-Site Scripting (XSS) — блокировка JavaScript-инъекций
- Remote Code Execution (RCE) — предотвращение выполнения системных команд
- Local File Inclusion (LFI) — защита от чтения локальных файлов
- Remote File Inclusion (RFI) — блокировка подключения внешних файлов
- Scanner Detection — обнаружение автоматических сканеров уязвимостей
- Protocol Violations — блокировка некорректных HTTP-запросов
Paranoia Levels
CRS имеет 4 уровня паранойи — от минимального до максимального:
Основа
30-60 минут
Мини-защита
1 день
Система
1-2 недели
Устойчивость
Постоянно
Установка ModSecurity + CRS
ModSecurity — самый популярный open-source WAF. Работает как модуль nginx или Apache. Рассмотрим установку с nginx.
# Установка зависимостей
apt update
apt install -y git build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev \
libssl-dev libgeoip-dev libyajl-dev libcurl4-openssl-dev
# Скачиваем ModSecurity
cd /opt
git clone --depth 1 -b v3/master https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure
make
make install
# Скачиваем коннектор для nginx
cd /opt
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx
# Пересобираем nginx с модулем ModSecurity
# (или используем динамический модуль если поддерживается)
cd /opt
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar xzf nginx-1.24.0.tar.gz
cd nginx-1.24.0
./configure --add-dynamic-module=/opt/ModSecurity-nginx \
--with-http_ssl_module --with-http_v2_module
make modules
cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
# Скачиваем OWASP CRS
cd /etc/nginx
git clone https://github.com/coreruleset/coreruleset
mv coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf
load_module modules/ngx_http_modsecurity_module.so;
http {
# Включаем ModSecurity
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# ... остальная конфигурация
}
# Основные настройки ModSecurity
Include /etc/nginx/modsec/modsecurity.conf
# Включаем OWASP CRS
Include /etc/nginx/coreruleset/crs-setup.conf
Include /etc/nginx/coreruleset/rules/*.conf
# Кастомные правила (опционально)
Include /etc/nginx/modsec/custom-rules.conf
# Режим работы:
# DetectionOnly — только логирование (для тестирования)
# On — активная блокировка
SecRuleEngine DetectionOnly
# Логирование
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/nginx/modsec_audit.log
# Лимиты
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
# Временные файлы
SecTmpDir /tmp/
SecDataDir /tmp/
# Включить парсинг JSON
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:200001,phase:1,t:none,t:lowercase,pass,ctl:requestBodyProcessor=JSON"
Cloudflare WAF
Cloudflare WAF — готовое решение, не требующее установки. На бесплатном плане доступны базовые правила, на Pro ($20/мес) — полный OWASP ruleset и кастомные правила.
Managed Rules
Cloudflare предоставляет несколько managed rulesets:
- Cloudflare Managed Ruleset — правила, созданные командой Cloudflare на основе анализа трафика. Автоматически обновляются.
- Cloudflare OWASP Core Ruleset — адаптация OWASP CRS для Cloudflare. Защита от SQLi, XSS, LFI и других классических атак.
- Exposed Credentials Check — проверяет логины/пароли против базы утёкших credentials.
Custom Rules (Firewall Rules)
Cloudflare позволяет создавать кастомные правила с помощью выражений на языке, похожем на SQL:
# Блокировать SQL-инъекции в query string
(http.request.uri.query contains "UNION SELECT" or
http.request.uri.query contains "OR 1=1" or
http.request.uri.query contains "DROP TABLE")
# Блокировать XSS в параметрах
(http.request.uri.query contains "<script" or
http.request.uri.query contains "javascript:" or
http.request.uri.query contains "onerror=")
# Защита админки — только определённые IP
(http.request.uri.path contains "/wp-admin" or
http.request.uri.path contains "/administrator") and
not ip.src in {1.2.3.4 5.6.7.8}
# Блокировка сканеров по User-Agent
(http.user_agent contains "sqlmap" or
http.user_agent contains "nikto" or
http.user_agent contains "nmap" or
http.user_agent contains "masscan")
# Rate limit на login endpoint
(http.request.uri.path eq "/api/login" and
http.request.method eq "POST")
# → Action: Rate Limiting, 5 req/10 sec
# Блокировка по threat score
cf.threat_score gt 20
# Требовать CAPTCHA для подозрительных запросов
cf.threat_score gt 5 and cf.threat_score le 20
# → Action: Managed Challenge
Защита от SQL Injection
SQL-инъекция — одна из старейших и опаснейших уязвимостей. Атакующий внедряет SQL-код в параметры, получая доступ к базе данных или возможность её модифицировать.
Паттерны SQL-инъекций
WAF обнаруживает SQLi по характерным паттернам:
UNION SELECT— объединение запросов для извлечения данныхOR 1=1,AND 1=1— обход условий WHERE; DROP TABLE— деструктивные командыSLEEP(),BENCHMARK()— time-based blind SQLi/*,--,#— комментарии для обхода фильтров0x...,CHAR()— кодирование payload
Кастомные правила ModSecurity
# Блокировка UNION-based инъекций
SecRule ARGS|ARGS_NAMES|REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_BODY \
"@rx (?i)union.+select" \
"id:100001,phase:2,deny,status:403,log,msg:'SQL Injection: UNION SELECT detected'"
# Блокировка классического 'OR 1=1'
SecRule ARGS|REQUEST_BODY \
"@rx (?i)(\bor\b|\band\b)\s+[\d\w]+\s*=\s*[\d\w]+" \
"id:100002,phase:2,deny,status:403,log,msg:'SQL Injection: Boolean-based SQLi'"
# Блокировка комментариев SQL в параметрах
SecRule ARGS|REQUEST_BODY \
"@rx (--|#|/\*)" \
"id:100003,phase:2,deny,status:403,log,msg:'SQL Injection: SQL comment detected'"
# Блокировка time-based blind SQLi
SecRule ARGS|REQUEST_BODY \
"@rx (?i)(sleep|benchmark|waitfor|delay)\s*\(" \
"id:100004,phase:2,deny,status:403,log,msg:'SQL Injection: Time-based function detected'"
# Исключения для легитимных endpoint'ов (пример)
SecRule REQUEST_URI "@beginsWith /api/code-editor" \
"id:100100,phase:1,pass,ctl:ruleRemoveById=100001-100004"
Защита от XSS
XSS (Cross-Site Scripting) позволяет атакующему внедрить JavaScript-код на страницу, который выполнится в браузере жертвы. Это может привести к краже cookies, перехвату сессий, фишингу.
Типы XSS
- Reflected XSS — payload в URL, отражается на странице
- Stored XSS — payload сохраняется в БД, выполняется для всех пользователей
- DOM-based XSS — payload манипулирует DOM напрямую в браузере
Паттерны XSS для WAF
# Блокировка <script> тегов
SecRule ARGS|ARGS_NAMES|REQUEST_BODY \
"@rx (?i)<\s*script[^>]*>" \
"id:100101,phase:2,deny,status:403,log,msg:'XSS: Script tag detected'"
# Блокировка javascript: URI
SecRule ARGS|REQUEST_BODY \
"@rx (?i)javascript\s*:" \
"id:100102,phase:2,deny,status:403,log,msg:'XSS: JavaScript URI detected'"
# Блокировка event handlers (onerror, onload, onclick, etc.)
SecRule ARGS|REQUEST_BODY \
"@rx (?i)on(error|load|click|mouseover|submit|focus|blur)\s*=" \
"id:100103,phase:2,deny,status:403,log,msg:'XSS: Event handler detected'"
# Блокировка data: URI с JavaScript
SecRule ARGS|REQUEST_BODY \
"@rx (?i)data\s*:\s*text/html" \
"id:100104,phase:2,deny,status:403,log,msg:'XSS: Data URI detected'"
# Блокировка expression() в CSS (старый IE)
SecRule ARGS|REQUEST_BODY \
"@rx (?i)expression\s*\(" \
"id:100105,phase:2,deny,status:403,log,msg:'XSS: CSS expression detected'"
# Блокировка SVG с JavaScript
SecRule ARGS|REQUEST_BODY \
"@rx (?i)<\s*svg[^>]*on\w+\s*=" \
"id:100106,phase:2,deny,status:403,log,msg:'XSS: SVG with event handler detected'"
Защита от L7 DDoS
WAF может эффективно защищать от L7 DDoS-атак — атак на уровне приложения, которые маскируются под легитимные HTTP-запросы.
Типы L7 DDoS
- HTTP Flood — множество GET/POST запросов
- Slowloris — медленные соединения, занимающие worker'ы
- R-U-Dead-Yet (RUDY) — медленная отправка POST body
- Application-specific — атака на тяжёлые endpoint'ы (поиск, отчёты)
Стратегии защиты
# Rate limiting: блокировка при превышении 60 запросов в минуту
SecAction "id:100200,phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR}"
SecAction "id:100201,phase:1,nolog,pass,setvar:ip.requests=+1"
SecRule IP:REQUESTS "@gt 60" \
"id:100202,phase:1,deny,status:429,log,msg:'Rate limit exceeded',setvar:ip.requests=0"
# Блокировка пустого или подозрительного User-Agent
SecRule REQUEST_HEADERS:User-Agent "@rx ^$" \
"id:100210,phase:1,deny,status:403,log,msg:'Empty User-Agent'"
SecRule REQUEST_HEADERS:User-Agent "@rx ^(curl|wget|python|perl|ruby|java)" \
"id:100211,phase:1,deny,status:403,log,msg:'Automated tool User-Agent'"
# Требование валидного Host заголовка
SecRule REQUEST_HEADERS:Host "!@rx ^(www\.)?example\.com$" \
"id:100220,phase:1,deny,status:403,log,msg:'Invalid Host header'"
# Блокировка Slowloris: лимит на время получения заголовков
SecAction "id:100230,phase:1,nolog,pass,setvar:'tx.inbound_anomaly_score_threshold=5'"
SecRule REQBODY_PROCESSOR_ERROR "@eq 1" \
"id:100231,phase:2,deny,status:400,msg:'Request body processing error'"
# Защита тяжёлых endpoint'ов
SecRule REQUEST_URI "@beginsWith /api/search" \
"id:100240,phase:1,chain,deny,status:429,log,msg:'Search rate limit'"
SecRule IP:SEARCH_REQUESTS "@gt 10" "setvar:ip.search_requests=0"
SecRule REQUEST_URI "@beginsWith /api/search" \
"id:100241,phase:1,nolog,pass,setvar:ip.search_requests=+1"
Тюнинг и исключения
Самая частая проблема с WAF — ложные срабатывания (false positives). Легитимные запросы блокируются, потому что похожи на атаки. Например:
- Программист пишет SQL-код в комментарии на форуме
- Администратор копирует JavaScript в настройки
- Длинный текст содержит слова, похожие на payload
- API принимает base64 или JSON с подозрительным содержимым
Процесс тюнинга
- Запуск в DetectionOnly — WAF логирует, но не блокирует
- Анализ логов — ищем false positives по реальному трафику
- Создание исключений — whitelist для легитимных паттернов
- Включение блокировки — переключаем в активный режим
- Мониторинг — отслеживаем новые false positives
# Исключение правила для конкретного URL
SecRule REQUEST_URI "@beginsWith /api/code" \
"id:100300,phase:1,pass,nolog,ctl:ruleRemoveById=941100-941999"
# Исключение параметра из проверки
SecRule ARGS:content "@rx ." \
"id:100301,phase:2,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content"
# Исключение по IP (для внутренних сервисов)
SecRule REMOTE_ADDR "@ipMatch 10.0.0.0/8,192.168.0.0/16" \
"id:100302,phase:1,pass,nolog,ctl:ruleEngine=Off"
# Исключение по User-Agent (для мониторинга)
SecRule REQUEST_HEADERS:User-Agent "@contains Pingdom" \
"id:100303,phase:1,pass,nolog,ctl:ruleRemoveById=920350"
# Исключение для конкретного правила на конкретном URL
SecRule REQUEST_URI "@eq /admin/settings" \
"id:100304,phase:1,pass,nolog,chain"
SecRule ARGS:config "@rx ." \
"ctl:ruleRemoveTargetById=942100;ARGS:config"
# Whitelist для загрузки файлов
SecRule REQUEST_URI "@beginsWith /upload" \
"id:100305,phase:1,pass,nolog,ctl:requestBodyAccess=Off"
Смотрите в audit log (modsec_audit.log для ModSecurity). Каждое срабатывание содержит rule ID, matched data, и другие детали. В Cloudflare — смотрите в Security → Events, там показывается rule ID и ray ID для каждого заблокированного запроса.
Используйте staging-окружение с копией продакшн-конфигурации. Или запустите правила в DetectionOnly режиме на продакшене — логируйте, но не блокируйте. Также можно использовать инструменты типа OWASP ZAP или Burp Suite для отправки тестовых payload'ов.
Да, но незначительно при правильной настройке. ModSecurity добавляет 1-5ms latency на запрос. Основная нагрузка — парсинг body и regex matching. Оптимизации: исключайте статику из проверки, используйте @pm (phrase match) вместо @rx (regex) где возможно, отключайте ненужные правила.