ModSecurity cu setul de reguli OWASP CRS se activează în zece minute și se dezactivează după trei zile — după ce articolele nu se mai salvează în administrare, se strică încărcarea fișierelor, iar clientul nu poate plasa o comandă pentru că adresa conținea un apostrof. Concluzia „WAF-ul încurcă munca” vine de la sine, dar este greșită: aproape toate aceste blocări se rezolvă cu trei-patru excepții punctuale, iar totul ține de a le găsi corect.
Nu activa blocarea imediat
Prima săptămână doar observare. În /etc/modsecurity/modsecurity.conf:
SecRuleEngine DetectionOnly
În acest mod, WAF-ul notează tot ce ar fi blocat, dar nu blochează nimic. O săptămână de trafic real — inclusiv munca ta în administrare, încărcarea imaginilor și plasarea unei comenzi — dă lista alarmelor false reale în loc de cele ipotetice. Comutarea pe On are sens abia după ce lista aceasta a fost parcursă.
Cum funcționează CRS: nu o regulă, ci o sumă
Cheia pentru tot ce urmează. CRS aproape niciodată nu blochează o cerere cu o singură regulă. Fiecare regulă declanșată adaugă cererii puncte de anomalie, iar blocarea are loc când suma depășește pragul. De aceea, în jurnal nu vei vedea o linie, ci mai multe, iar ultima va fi regula cu identificatorul 949110 — cea care face totalul.
Concluzia practică: excepția trebuie făcută pentru regula care a adăugat puncte, nu pentru 949110. Dezactivând regula de totalizare, dezactivezi întregul set, iar WAF-ul rămâne doar ca o linie în configurație.
A doua consecință este nivelul de paranoia. Implicit este primul, și aceasta este alegerea corectă. Nivelurile 2 și 3 adaugă reguli care produc cu siguranță alarme false pe site-uri obișnuite, iar activarea lor are sens abia când primul nivel este reglat complet.
Găsirea regulii vinovate
Tot ce trebuie se află în jurnalul de audit (/var/log/modsec_audit.log) și în jurnalul de erori al serverului web. Căutăm după momentul blocării:
sudo grep -o 'id "[0-9]*"' /var/log/modsec_audit.log | sort | uniq -c | sort -rn | head
Aceasta este lista de frecvență a regulilor declanșate. Apoi, pentru un identificator anume, ne uităm pe ce anume s-a declanșat:
sudo grep -A5 'id "942100"' /var/log/modsec_audit.log | head -40
Sunt necesare trei lucruri: identificatorul regulii, numele parametrului (ARGS:content, ARGS:comment) și calea cererii. Din ele se construiește excepția.
Suspecții obișnuiți
Lista se repetă de la site la site:
- 942100 — injecție SQL. Se declanșează pe câmpuri de text cu conținut lung: corpul articolului, descrierea produsului, comentariul. Apostrofurile, parantezele și cuvinte precum
selectpar suspecte detectorului chiar și în text normal; - 941100 și 941xxx — XSS. Vin împreună cu editorul vizual: etichetele HTML în câmp sunt tot rostul funcționării lui;
- 920420 — Content-Type nepermis. Strică API-urile și încărcarea fișierelor: setul implicit de tipuri permise este îngust, iar
application/jsonnu intra în el în versiunile mai vechi; - 913100 — scaner după User-Agent. Prinde împreună cu scanerele și instrumente legitime: monitorizarea disponibilității, curl în propriile tale scripturi;
- 200002, 200004 — erori la parsarea corpului cererii. De obicei nu înseamnă atac, ci depășirea limitei de dimensiune a corpului, adică încărcarea unui fișier mare.
Trei moduri de a face o excepție
În ordinea crescătoare a grosolăniei. Toate se scriu într-un fișier propriu (de exemplu /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES.conf), nu în fișierele CRS: setul de reguli se actualizează, iar modificările tale dispar la actualizare.
Scoaterea unui parametru de sub o regulă. Varianta cea mai precisă, spre care tindem:
SecRuleUpdateTargetById 942100 "!ARGS:content"
Dezactivarea regulii doar pe o cale. Se potrivește când „face zgomot” o anumită pagină — editorul, importul, formularul de recenzie:
SecRule REQUEST_URI "@beginsWith /admin/post" \
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"
Dezactivarea completă a regulii. Măsură extremă și aproape întotdeauna semn că nu a fost găsită cauza:
SecRuleRemoveById 942100
Diferența dintre prima și a treia variantă este esențială. În primul caz, câmpul „textul articolului” încetează să fie verificat pentru injecții SQL de o singură regulă; în al doilea și al treilea încetează să fie verificat întregul site. Diferența de efort este de vreo cinci minute.
După modificări — verificarea configurației și repornirea lină:
sudo apachectl configtest && sudo systemctl reload apache2
sudo nginx -t && sudo systemctl reload nginx
Ordinea care economisește o săptămână
- O săptămână în
DetectionOnly, cu muncă obișnuită pe site, inclusiv administrarea și încărcările. - Lista de frecvență a regulilor din jurnalul de audit. Parcurge de sus în jos — primele trei-patru dau nouăzeci la sută din zgomot.
- Pentru fiecare: află ce parametru și pe ce pagină. Fă excepția după parametru, nu după regulă.
- Abia acum
SecRuleEngine On. - O dată pe lună aruncă o privire peste blocări: dacă site-ul s-a schimbat, apar alarme false noi.
Ultimul punct este cel de care se împiedică totul de obicei: jurnalul de audit înseamnă gigaocteți de text, nimeni nu îl va citi manual. Rostul unui panou adunat este ca lista regulilor declanșate, a cererilor blocate și setul activ să fie în fața ochilor, nu să fie scoase cu grep. Cum arată asta arată pagina demonstrativă de mai jos.