ModSecurity med regelsettet OWASP CRS slås på på ti minutter og av tre dager senere — etter at artikler har sluttet å lagres i administrasjonsgrensesnittet, filopplastingen har brutt sammen og kunden ikke får lagt inn en bestilling fordi adressen tilfeldigvis inneholdt en apostrof. Konklusjonen «WAF-en er i veien» ligger snublende nær, men den er feil: nesten alle disse blokkeringene løses med tre eller fire målrettede unntak, og hele saken handler om å finne dem på riktig måte.

Ikke slå på blokkering med en gang

Den første uken er ren observasjon. I /etc/modsecurity/modsecurity.conf:

SecRuleEngine DetectionOnly

I den modusen noterer WAF-en alt den ville ha blokkert, men blokkerer ingenting. En uke med virkelig trafikk — inkludert ditt eget arbeid i administrasjonsgrensesnittet, bildeopplasting og en bestilling — gir listen over faktiske falske utslag i stedet for hypotetiske. Å bytte til On gir mening først når den listen er gjennomgått.

Slik virker CRS: ikke én regel, men en sum

Nøkkelen til alt som følger. CRS blokkerer nesten aldri en forespørsel med én enkelt regel. Hver regel som utløses, legger anomalipoeng til forespørselen, og blokkeringen skjer når summen overstiger terskelen. Derfor ser du ikke én linje i loggen, men flere, og den siste er regelen med id 949110 — den som summerer.

Praktisk konklusjon: unntaket skal lages for regelen som ga poengene, ikke for 949110. Slår du av den summerende regelen, slår du av hele settet, og WAF-en blir bare igjen som en linje i konfigurasjonen.

Neste følge er paranoianivået. Som standard er det ett, og det er riktig valg. Nivå 2 og 3 legger til regler som med sikkerhet gir falske utslag på vanlige nettsteder, og de bør slås på først når nivå én er ferdig innkjørt.

Finn den skyldige regelen

Alt du trenger, finnes i revisjonsloggen (/var/log/modsec_audit.log) og i webserverens feillogg. Vi søker på blokkeringstidspunktet:

sudo grep -o 'id "[0-9]*"' /var/log/modsec_audit.log | sort | uniq -c | sort -rn | head

Det er en frekvensliste over utløste regler. Deretter ser vi på hva en bestemt id faktisk ble utløst av:

sudo grep -A5 'id "942100"' /var/log/modsec_audit.log | head -40

Tre ting trengs: regelens id, parameterens navn (ARGS:content, ARGS:comment) og forespørselens sti. Av dem bygges unntaket.

De vanlige mistenkte

Listen gjentar seg fra nettsted til nettsted:

  • 942100 — SQL-injeksjon. Utløses på tekstfelt med langt innhold: artikkeltekst, produktbeskrivelse, kommentar. Apostrofer, parenteser og ord som select ser mistenkelige ut for detektoren selv i vanlig tekst;
  • 941100 og 941xxx — XSS. Kommer sammen med en visuell redigerer: HTML-tagger i feltet er hele arbeidsmåten dens;
  • 920420 — ikke tillatt Content-Type. Ødelegger API-er og filopplasting: standardsettet av tillatte typer er smalt, og application/json inngikk ikke i eldre versjoner;
  • 913100 — skanner etter User-Agent. Fanger legitime verktøy sammen med skannerne: tilgjengelighetsovervåking, curl i dine egne skript;
  • 200002, 200004 — feil ved tolking av forespørselens kropp. Betyr som regel ikke et angrep, men en overskredet størrelsesgrense, altså opplasting av en stor fil.

Tre måter å lage unntak på

I stigende grovhet. Alle skrives i en egen fil (for eksempel /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES.conf) og ikke i CRS sine egne filer: regelsettet oppdateres, og endringene dine forsvinner ved oppdateringen.

Ta en parameter ut fra én regel. Det mest presise alternativet, og det vi sikter mot:

SecRuleUpdateTargetById 942100 "!ARGS:content"

Slå av regelen bare på én sti. Passer når en bestemt side støyer — redigereren, importen, tilbakemeldingsskjemaet:

SecRule REQUEST_URI "@beginsWith /admin/post" \
    "id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"

Slå av regelen helt. Siste utvei og nesten alltid et tegn på at årsaken ikke er funnet:

SecRuleRemoveById 942100

Forskjellen mellom det første og det tredje er betydelig. I det første tilfellet slutter feltet «artikkeltekst» å kontrolleres mot SQL-injeksjoner av én regel; i det andre og tredje slutter hele nettstedet å kontrolleres. Forskjellen i arbeidsinnsats er rundt fem minutter.

Etter endringene — konfigurasjonskontroll og myk omlasting:

sudo apachectl configtest && sudo systemctl reload apache2
sudo nginx -t && sudo systemctl reload nginx

Rekkefølgen som sparer en uke

  1. En uke i DetectionOnly med vanlig arbeid på nettstedet, inkludert administrasjonsgrensesnittet og opplastinger.
  2. Frekvenslisten over regler fra revisjonsloggen. Gå ovenfra og ned — de tre første gir nitti prosent av støyen.
  3. For hver av dem: finn ut hvilken parameter og hvilken side det gjelder. Lag unntaket per parameter, ikke per regel.
  4. Først nå SecRuleEngine On.
  5. Se på blokkeringene én gang i måneden: når nettstedet endres, dukker det opp nye falske utslag.

Det siste punktet er det alt vanligvis strander på: revisjonsloggen er gigabyte med tekst, og ingen leser den for hånd. Poenget med et samlet panel er at listen over utløste regler, blokkerte forespørsler og det aktive settet ligger foran øynene i stedet for å graves fram med grep. Hvordan det ser ut, viser demonstrasjonssiden nedenfor.