På angreppskartan ligger en tät fläck över ett land, och regeln ”förbjud det helt” anmäler sig av sig själv. Den ger nästan ingenting: att byta utgångsland kostar angriparen några minuter, medan förbudet träffar dina egna besökare och dig själv på resa. Värre ändå: en synlig crawler från ett enda moln flyttar efter blockeringen över till privatadresser och blir omöjlig att skilja från människor.

Nedan följer fem steg som faktiskt ger resultat på samma server: kapa skannrarna, begränsa tempot, låt bli att kapa det nödvändiga och blockera rätt om det ändå behövs. Allt går att kontrollera och ställa in vid ett och samma tillfälle.

Steg 1. Se vem som faktiskt skapar fläcken

Leta först upp loggen över förfrågningar. På en server med flera webbplatser är access.log ofta tom, medan raderna hamnar i loggen för den enskilda virtuella värden:

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

I alla kommandon nedan sätts den fil in som hamnade överst i den listan. Först adresserna som leder för dygnet, sedan vad den översta faktiskt 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

Det andra kommandot svarar på huvudfrågan. Står det tiotals olika sidor från din egen webbplats i utskriften är det en innehållssamlare: ofarlig, och det räcker att inte räkna den som besökare. Står det /wp-login.php, /.env, /phpmyadmin och annat som du inte har, är det en skanner, och den tar steg 2 hand om. Vid nginx ligger loggarna i /var/log/nginx/, fälten är desamma.

Steg 2. Ett jail mot förfrågningar efter sådant du inte har

Den begärda sökvägen går inte att förfalska — den är själva avsikten, till skillnad från adressen och User-Agent. Filtret /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

Här är maxretry = 1 befogat: ingen hamnar av en slump på någon annans administrationssida. Tillämpa det och kontrollera att filtret fångar rader 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

Steg 3. Begränsa tempot

Skannern och crawlern röjer sig genom hastigheten, oavsett vilket land de kommer från. Trettio sidor i minuten från en enda adress är en gräns som inte träffar en människa som bläddrar 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 avgörande är vilken logg som anges i logpath. Faller loggen för själva kontrollpanelen eller administrationsdelen in under mönstret blockerar du dig själv: en enda sida där drar med sig ett dussin förfrågningar efter stilmallar och skript, och trettio når man upp i på två klick. Därför ger man panelen en egen loggfil som inte stämmer med jailets mönster, och statiska filer en lång cachetid så att webbläsaren inte begär dem på nytt vid varje sidbyte. Symtomet, om det ändå inträffar: HTML-koden kommer fram, formgivningen gör det inte, sidan hänger. Häva blockeringen:

sudo fail2ban-client set http-flood unbanip 203.0.113.10

Steg 4. Skydda det som inte får kapas

Skriv ned undantagen innan du slår på blockeringar — annars är det första de träffar just det nödvändiga:

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

Vad som ovillkorligen hör hemma på den raden, och varför:

  • Din egen adress eller kontorets delnät. Den vanligaste orsaken till förlorad åtkomst till en server är den egna regeln, inte ett angrepp;
  • Intervallet 66.249.64.0/19. Googles sökrobot ger sig till känna via User-Agent, men den del av den som kör JavaScript kommer som en helt vanlig Chrome/Linux och nämner inte sig själv. Varje regel av typen ”blockera trafik från datacenter” träffar just den, varefter sidor tyst faller ur indexet. En misstänkt adress kan kontrolleras med en omvänd förfrågan: dig -x 66.249.66.1 +short ska ge ett namn i zonen googlebot.com;
  • Adresserna som betalningsaviseringarna kommer från. Webhookar från betalsystem kommer från AWS- och Azure-servrar. Stänger du de molnen helt slutar betalningsbekräftelserna att nå fram, och du märker det den dag en kund skriver att pengarna är dragna men åtkomsten uteblir. Intervallen hämtas ur dokumentationen hos din betalningsleverantör.

Steg 5. Om en blockering ändå behövs — blockera ett delnät, inte ett land

En ihållande förtätning från ett enda nät som håller i sig i dagar och åtföljs av likartade förfrågningar är en enskild utförare som arbetar sig igenom en lista. Det fallet blockeras punktvis och tidsbegränsat:

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

Notera regelns nummer med det andra kommandot: blockeringen måste senare hävas just genom det, sudo ufw delete <nummer>. Kom överens med dig själv om en tidsgräns — exempelvis en månad — och skriv in hävningen i kalendern. Regler som satts ”för alltid” blir efter ett år en lista som ingen vågar röra, eftersom ingen minns vad de adresserna gjorde för att hamna där.

Vilket delnät som ska blockeras kan du ta reda på utifrån adressen från första steget: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.

Vad som förändras efter dessa fem steg

Skannrar kapas efter avsikt och inte efter ursprung, och fångas vid den första förfrågan. Crawlrar stöter emot tempogränsen. Sökroboten och betalningsaviseringarna kommer fortfarande fram. Den enda blockering som blivit bred är punktvis, med en känd tidsgräns och ett begripligt skäl.

Kartan försvinner inte för det, men dess roll förändras: den finns inte till för att stänga ute länder, utan för att över huvud taget upptäcka förtätningen och jämföra den med hur det såg ut för en vecka sedan. Till det behövs en historik och inte en ögonblicksbild av det pågående dygnet. Hur en sådan karta ser ut tillsammans med blockeringsloggen och listan över öppna portar visar demosidorna nedan.