Op de aanvalskaart ligt een dichte vlek boven één land, en de regel «dat land helemaal verbieden» dringt zich op. Ze levert bijna niets op: het land van uitgang wisselen kost de aanvaller enkele minuten, terwijl je eigen bezoekers en jij zelf op reis onder het verbod vallen. Erger nog: een zichtbare crawler uit één enkele cloud verhuist na de blokkade naar woonadressen en is dan niet meer van mensen te onderscheiden.
Hieronder staan vijf stappen die op diezelfde server wel resultaat geven: scanners afsnijden, het tempo begrenzen, het nodige niet mee afsnijden en, als het toch nodig blijkt, correct blokkeren. Alles is in één zitting te controleren en in te stellen.
Stap 1. Kijken wie de vlek werkelijk veroorzaakt
Zoek eerst het verzoekenlogboek op. Op een server met meerdere sites is access.log vaak leeg, terwijl de regels in het logboek van de betreffende virtuele host terechtkomen:
sudo ls -lS /var/log/apache2/*access*.log /var/log/apache2/*requests*.log 2>/dev/null
In alle verdere commando’s vul je het bestand in dat bovenaan die lijst staat. Eerst de adressen die de dag aanvoeren, dan wat degene bovenaan precies opvraagt:
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
Het tweede commando geeft antwoord op de hoofdvraag. Staan er in de uitvoer tientallen verschillende pagina’s van je eigen site, dan is het een inhoudsverzamelaar: onschadelijk, en het is genoeg hem niet als bezoeker te tellen. Staat er /wp-login.php, /.env, /phpmyadmin en ander spul dat je niet hebt, dan is het een scanner, en daarmee gaat stap 2 om. Bij nginx liggen de logboeken in /var/log/nginx/, de velden zijn dezelfde.
Stap 2. Een jail voor verzoeken naar iets dat je niet hebt
Het opgevraagde pad valt niet te vervalsen — het is de bedoeling zelf, anders dan het adres en de User-Agent. Het filter /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 =
De jail /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
maxretry = 1 is hier gerechtvaardigd: toevallige bezoeken aan het beheerpaneel van een ander bestaan niet. Toepassen en nagaan of het filter regels in je eigen logboek oppikt:
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
Stap 3. Het tempo begrenzen
Een scanner en een crawler verraden zich door hun snelheid, uit welk land ze ook komen. Dertig pagina’s per minuut van één adres is een grens die iemand die een catalogus doorbladert niet raakt:
[http-flood]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/site_access.log
maxretry = 30
findtime = 60
bantime = 1h
Het beslissende detail is welk logboek in logpath staat. Valt het logboek van het beheerpaneel zelf of van het beheergedeelte ook onder het patroon, dan blokkeer je jezelf: één pagina daar trekt een tiental verzoeken naar stijlen en scripts mee, en dertig zijn in twee klikken bereikt. Daarom geeft men het paneel een eigen logbestand dat niet op het patroon van de jail past, en statische bestanden een lange cacheduur, zodat de browser ze niet bij elke pagina opnieuw opvraagt. Het symptoom als het toch gebeurt: de HTML komt aan, de opmaak niet, de pagina blijft hangen. Blokkade opheffen:
sudo fail2ban-client set http-flood unbanip 203.0.113.10
Stap 4. Beschermen wat niet afgesneden mag worden
Schrijf de uitzonderingen op voordat je blokkades aanzet — anders valt juist het nodige er als eerste onder:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 66.249.64.0/19
Wat er beslist in die regel hoort en waarom:
- Je eigen adres of het subnet van het kantoor. De meest voorkomende oorzaak van verloren toegang tot een server is je eigen regel, niet een aanval;
- Het bereik
66.249.64.0/19. De zoekrobot van Google maakt zich kenbaar via de User-Agent, maar het deel ervan dat JavaScript uitvoert komt binnen als een gewoneChrome/Linuxen noemt zich niet. Elke regel van het type «verkeer uit datacentra blokkeren» raakt precies dat deel, waarna pagina’s stil uit de index vallen. Een verdacht adres kun je nagaan met een omgekeerde opvraging:dig -x 66.249.66.1 +shortmoet een naam in de zonegooglebot.comteruggeven; - De adressen van de betalingsmeldingen. Webhooks van betaalsystemen komen van AWS- en Azure-servers. Sluit je die clouds helemaal af, dan komen betalingsbevestigingen niet meer aan, en je komt dat te weten op de dag dat een klant schrijft dat het geld is afgeschreven maar de toegang er niet is. De bereiken staan in de documentatie van je betaaldienst.
Stap 5. Als een blokkade toch nodig is: blokkeer een subnet, geen land
Een blijvende verdichting uit één netwerk die dagen aanhoudt en met eenvormige verzoeken gepaard gaat, is één uitvoerder die een lijst afwerkt. Zo’n geval wordt gericht en tijdelijk geblokkeerd:
sudo ufw deny from 198.51.100.0/22 to any
sudo ufw status numbered
Noteer met het tweede commando het regelnummer: de blokkade moet er later ook mee worden opgeheven, sudo ufw delete <nummer>. Spreek met jezelf een termijn af — bijvoorbeeld een maand — en zet het opheffen in de agenda. Regels die «voor altijd» zijn gezet, worden na een jaar een lijst die niemand aandurft, omdat niemand zich herinnert waarvoor die adressen er zijn beland.
Welk subnet je moet blokkeren, kun je achterhalen via het adres uit de eerste stap: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.
Wat er na deze vijf stappen verandert
Scanners worden op bedoeling afgesneden en niet op herkomst, en worden bij het eerste verzoek gepakt. Crawlers lopen tegen de tempolimiet aan. De zoekrobot en de betalingsmeldingen blijven doorkomen. De enige blokkade die breed is gebleven, is gericht, met een bekende termijn en een begrijpelijke reden.
De kaart verdwijnt daarbij niet, maar haar rol verandert: ze is er niet om landen af te sluiten, maar om de verdichting überhaupt op te merken en te vergelijken met die van een week eerder. Daarvoor is een geschiedenis nodig en geen momentopname van de huidige dag. Hoe zo’n kaart eruitziet naast het blokkadelogboek en de lijst van open poorten, laten de demopagina’s hieronder zien.