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 select par 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/json nu 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ă

  1. O săptămână în DetectionOnly, cu muncă obișnuită pe site, inclusiv administrarea și încărcările.
  2. Lista de frecvență a regulilor din jurnalul de audit. Parcurge de sus în jos — primele trei-patru dau nouăzeci la sută din zgomot.
  3. Pentru fiecare: află ce parametru și pe ce pagină. Fă excepția după parametru, nu după regulă.
  4. Abia acum SecRuleEngine On.
  5. 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.