ModSecurity із набором правил OWASP CRS вмикають за десять хвилин і вимикають за три дні — після того, як статті перестають зберігатися в адмінці, ламається завантаження файлів, а клієнт не може оформити замовлення, бо в його адресі був апостроф. Висновок «WAF заважає працювати» напрошується сам, і він хибний: майже всі ці блокування лікуються трьома-чотирма точними винятками, і вся хитрість — знайти їх правильно.
Не вмикайте блокування одразу
Перший тиждень — лише спостереження. У /etc/modsecurity/modsecurity.conf:
SecRuleEngine DetectionOnly
У цьому режимі WAF записує все, що заблокував би, і не блокує нічого. Тиждень реального трафіку — разом із вашою роботою в адмінці, завантаженням картинок і оформленням замовлення — дає список справжніх хибних спрацювань, а не гіпотетичних. Перехід на On має сенс лише після того, як цей список розібрано.
Як працює CRS: не одне правило, а сума
Це ключ до всього, що йде далі. CRS майже ніколи не блокує запит одним правилом. Кожне спрацьоване правило додає запиту балів аномальності, а блокування настає, коли сума переходить поріг. Тому в журналі не один рядок, а кілька, і тому останній з них — правило з ідентифікатором 949110, те, що підбиває підсумок.
Практичний наслідок: виняток треба робити для правила, яке нарахувало бали, а не для 949110. Вимкнете правило-суматор — вимкнете весь набір, і WAF залишиться рядком у конфігураційному файлі.
Другий наслідок — рівень параної. Типово він дорівнює одиниці, і це правильний вибір. Рівні 2 і 3 додають правила, які на звичайних сайтах дають хибні спрацювання за задумом, і вмикати їх варто лише тоді, коли перший рівень налаштовано повністю.
Знайдіть винне правило
Усе потрібне є в журналі аудиту (/var/log/modsec_audit.log) і в журналі помилок вебсервера. Шукайте за часом блокування:
sudo grep -o 'id "[0-9]*"' /var/log/modsec_audit.log | sort | uniq -c | sort -rn | head
Це список частоти правил, які спрацювали. Потім для конкретного ідентифікатора подивіться, що саме його викликало:
sudo grep -A5 'id "942100"' /var/log/modsec_audit.log | head -40
Потрібні три речі: ідентифікатор правила, назва параметра (ARGS:content, ARGS:comment) і шлях запиту. З них будується виняток.
Звичні підозрювані
Список повторюється від сайту до сайту:
- 942100 — SQL-ін’єкція. Спрацьовує на текстових полях із довгим вмістом: тіло статті, опис товару, коментар. Лапки, дужки та слова на кшталт
selectздаються детектору підозрілими всередині звичайної прози; - 941100 і сімейство 941xxx — XSS. Приходять разом із візуальним редактором: HTML-теги в полі — це і є весь сенс того, як він працює;
- 920420 — недозволений Content-Type. Ламає API та завантаження файлів: типовий набір дозволених типів вузький, а в старих версіях
application/jsonу ньому не було; - 913100 — сканер за User-Agent. Ловить легітимні інструменти разом зі сканерами: моніторинг доступності, curl у ваших власних скриптах;
- 200002, 200004 — помилки розбору тіла запиту. Зазвичай означають не атаку, а перевищений ліміт розміру тіла, тобто завантаження великого файла.
Три способи зробити виняток
За зростанням грубості. Усі вони йдуть у ваш власний файл (наприклад, /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES.conf), а не у файли самого CRS: набір правил оновлюється, і ваші правки зникнуть разом із ним.
Прибрати один параметр з-під одного правила. Найточніший варіант і той, до якого варто прагнути:
SecRuleUpdateTargetById 942100 "!ARGS:content"
Вимкнути правило лише на одному шляху. Саме тоді, коли шумить конкретна сторінка — редактор, імпорт, форма відгуку:
SecRule REQUEST_URI "@beginsWith /admin/post" \
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"
Вимкнути правило повністю. Останній засіб і майже завжди ознака того, що причину так і не знайшли:
SecRuleRemoveById 942100
Різниця між першим і третім суттєва. У першому випадку одне поле — тіло статті — перестає перевірятися на SQL-ін’єкцію одним правилом; у другому й третьому перевірятися перестає весь сайт. Різниця у зусиллях — близько п’яти хвилин.
Після правок перевірте конфігурацію і м’яко перезавантажте:
sudo apachectl configtest && sudo systemctl reload apache2
sudo nginx -t && sudo systemctl reload nginx
Порядок, який економить тиждень
- Тиждень у
DetectionOnlyзі звичайною роботою на сайті, в адмінці та із завантаженнями. - Список частоти правил із журналу аудиту. Ідіть згори вниз — перші три-чотири дають дев’яносто відсотків шуму.
- Для кожного: з’ясуйте, який параметр і на якій сторінці. Робіть виняток за параметром, а не за правилом.
- І лише тепер
SecRuleEngine On. - Раз на місяць заглядайте в блокування: сайт змінився, отже, з’явилися нові хибні спрацювання.
Саме на цьому останньому пункті все зазвичай і розсипається: журнал аудиту — це гігабайти тексту, і руками його ніхто не читатиме. Сенс зібраної панелі в тому, щоб список спрацьованих правил, заблоковані запити й активний набір правил були перед очима, а не діставалися grep-ом. Який вигляд це має, показує демосторінка нижче.