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

Редът, който спестява седмица

  1. Седмица в DetectionOnly с обичайна работа на сайта, включително администрацията и качванията.
  2. Честотният списък на правилата от одитния журнал. Обработвайте отгоре надолу — първите три-четири дават деветдесет процента от шума.
  3. За всяко: разберете кой параметър и на коя страница. Изключението правете по параметър, а не по правило.
  4. Едва сега SecRuleEngine On.
  5. Веднъж месечно поглеждайте блокировките: сайтът се е променил — появили са се нови фалшиви сигнали.

Последната точка е това, в което всичко обикновено се проваля: одитният журнал е гигабайти текст, ръчно никой няма да го чете. Смисълът на събрания панел е списъкът на задействалите се правила, блокираните заявки и активният набор да са пред очите, а не да се вадят с grep. Как изглежда това, показва демонстрационната страница по-долу.