På angrepskartet ligger en tett flekk over ett land, og regelen «forby det i sin helhet» melder seg av seg selv. Den gir nesten ingenting: å bytte utgangsland koster angriperen noen minutter, mens forbudet rammer dine egne besøkende og deg selv på reise. Verre ennå: en synlig crawler fra én enkelt sky flytter etter blokkeringen over på private adresser og blir umulig å skille fra mennesker.

Nedenfor er fem trinn som faktisk gir resultat på den samme serveren: kutt skannerne, begrens tempoet, la være å kutte det nødvendige, og blokker riktig hvis det likevel trengs. Alt kan kontrolleres og settes opp på én økt.

Trinn 1. Se hvem som faktisk lager flekken

Finn først loggen over forespørsler. På en server med flere nettsteder er access.log ofte tom, mens linjene havner i loggen til den enkelte virtuelle verten:

sudo ls -lS /var/log/apache2/*access*.log /var/log/apache2/*requests*.log 2>/dev/null

I alle kommandoene videre settes inn den filen som havnet øverst på listen. Først adressene som leder for døgnet, deretter hva den øverste faktisk ber om:

sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
sudo grep '^203\.0\.113\.' /var/log/apache2/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

Den andre kommandoen svarer på hovedspørsmålet. Står det titalls forskjellige sider fra ditt eget nettsted i utskriften, er det en innholdssamler: ufarlig, og det holder å ikke telle den som besøkende. Står det /wp-login.php, /.env, /phpmyadmin og annet du ikke har, er det en skanner, og den tar trinn 2 seg av. Ved nginx ligger loggene i /var/log/nginx/, feltene er de samme.

Trinn 2. Et jail mot forespørsler etter noe du ikke har

Den forespurte stien kan ikke forfalskes — den er selve hensikten, i motsetning til adressen og User-Agent. Filteret /etc/fail2ban/filter.d/web-probes.local:

[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login\.php|wp-admin|xmlrpc\.php|\.env|\.git/|phpmyadmin|administrator/)
ignoreregex =

Jailet /etc/fail2ban/jail.d/web-probes.local:

[web-probes]
enabled  = true
port     = http,https
filter   = web-probes
logpath  = /var/log/apache2/*access.log
maxretry = 1
findtime = 1h
bantime  = 1d

Her er maxretry = 1 berettiget: ingen havner tilfeldig på en annens administrasjonsside. Ta det i bruk og kontroller at filteret fanger linjer i din egen logg:

sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/web-probes.local
sudo systemctl reload fail2ban && sudo fail2ban-client status web-probes

Trinn 3. Begrens tempoet

Skanneren og crawleren røper seg med farten, uansett hvilket land de kommer fra. Tretti sider i minuttet fra én adresse er en grense som ikke rammer et menneske som blar i en katalog:

[http-flood]
enabled  = true
port     = http,https
filter   = apache-overflows
logpath  = /var/log/apache2/site_access.log
maxretry = 30
findtime = 60
bantime  = 1h

Det avgjørende er hvilken logg som står i logpath. Faller loggen til selve kontrollpanelet eller administrasjonsdelen inn under mønsteret, blokkerer du deg selv: én enkelt side der drar med seg et dusin forespørsler etter stilark og skript, og tretti når man opp i med to klikk. Derfor gir man panelet sin egen loggfil som ikke passer med jailets mønster, og statiske filer en lang mellomlagringstid, slik at nettleseren ikke ber om dem på nytt ved hvert sideskifte. Symptomet, hvis det likevel skjer: HTML-koden kommer fram, utseendet gjør det ikke, siden henger. Oppheve blokkeringen:

sudo fail2ban-client set http-flood unbanip 203.0.113.10

Trinn 4. Beskytt det som ikke må kuttes

Skriv ned unntakene før du slår på blokkeringer — ellers er det første de rammer, nettopp det nødvendige:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 66.249.64.0/19

Hva som ubetinget hører hjemme på den linjen, og hvorfor:

  • Din egen adresse eller kontorets delnett. Den vanligste årsaken til å miste tilgang til en server er ens egen regel, ikke et angrep;
  • Området 66.249.64.0/19. Googles søkerobot gir seg til kjenne gjennom User-Agent, men den delen av den som kjører JavaScript, kommer som en helt vanlig Chrome/Linux og nevner ikke seg selv. Enhver regel av typen «blokker trafikk fra datasentre» rammer nettopp den, hvoretter sider stille faller ut av indeksen. En mistenkelig adresse kan kontrolleres med et omvendt oppslag: dig -x 66.249.66.1 +short skal gi et navn i sonen googlebot.com;
  • Adressene betalingsvarslene kommer fra. Webhooks fra betalingssystemer kommer fra AWS- og Azure-servere. Stenger du de skyene helt, slutter betalingsbekreftelsene å komme fram, og du oppdager det den dagen en kunde skriver at pengene er trukket, men tilgangen mangler. Områdene står i dokumentasjonen til betalingsleverandøren din.

Trinn 5. Hvis en blokkering likevel trengs — blokker et delnett, ikke et land

En vedvarende fortetning fra ett enkelt nett som holder seg i dagevis og følges av ensartede forespørsler, er én utøver som arbeider seg gjennom en liste. Det tilfellet blokkeres presist og tidsbegrenset:

sudo ufw deny from 198.51.100.0/22 to any
sudo ufw status numbered

Noter regelens nummer med den andre kommandoen: blokkeringen må senere oppheves nettopp gjennom det, sudo ufw delete <nummer>. Avtal en frist med deg selv — for eksempel en måned — og skriv opphevingen i kalenderen. Regler satt «for alltid» blir etter et år til en liste ingen tør røre, fordi ingen husker hva de adressene gjorde for å havne der.

Hvilket delnett som skal blokkeres, finner du ut fra adressen i første trinn: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.

Hva som endrer seg etter disse fem trinnene

Skannere kuttes etter hensikt og ikke etter opphav, og fanges ved den første forespørselen. Crawlere støter mot tempogrensen. Søkeroboten og betalingsvarslene kommer fortsatt gjennom. Den eneste blokkeringen som er blitt bred, er presis, med en kjent frist og en forståelig grunn.

Kartet forsvinner ikke av den grunn, men rollen endrer seg: det er ikke der for å stenge land ute, men for i det hele tatt å få øye på fortetningen og sammenligne den med uken før. Til det trengs en historikk og ikke et øyeblikksbilde av det inneværende døgnet. Hvordan et slikt kart ser ut sammen med blokkeringsloggen og listen over åpne porter, viser demosidene nedenfor.