Na mapě útoků je hustá skvrna nad jednou zemí a samo se nabízí pravidlo „zakázat ji celou“. Nepřinese to skoro nic: změnit zemi výstupu stojí útočníka pár minut, pod zákaz ale spadnou vaši vlastní návštěvníci a vy sami na cestách. Co hůř, viditelný robot přicházející z jednoho cloudu se po zablokování přestěhuje na domácí adresy a přestane být od lidí rozeznatelný.

Níže je pět kroků, které na témže serveru výsledek skutečně dají: odříznout skenery, omezit tempo, neodříznout to potřebné a — pokud je to opravdu nutné — zablokovat správně. Všechno se dá ověřit a nastavit na jedno posezení.

Krok 1. Podívat se, kdo skvrnu vlastně vytváří

Nejdřív najděte protokol požadavků. Na serveru s několika weby bývá access.log prázdný, zatímco záznamy jdou do protokolu konkrétního virtuálního hostitele:

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

Ve všech dalších příkazech se dosazuje soubor, který se octl na začátku tohoto výpisu. Nejdřív vedoucí adresy za den, pak to, oč přesně žádá ta nahoře:

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

Druhý příkaz odpovídá na hlavní otázku. Jsou-li ve výstupu desítky různých stránek vašeho webu, jde o sběrač obsahu: je neškodný a stačí ho nepočítat jako návštěvníka. Je-li tam /wp-login.php, /.env, /phpmyadmin a další věci, které nemáte, jde o skener, a tím se zabývá krok 2. U nginx leží protokoly v /var/log/nginx/, pole jsou stejná.

Krok 2. Jail na požadavky na to, co nemáte

Cestu požadavku nelze zfalšovat — ona sama je záměrem, na rozdíl od adresy a User-Agenta. Filtr /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 =

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

Zde je maxretry = 1 oprávněné: náhodné přístupy do cizí administrace neexistují. Použít a ověřit, že filtr zabírá na záznamy ve vašem protokolu:

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

Krok 3. Omezit tempo

Skener i robot se prozradí rychlostí, nezávisle na tom, z jaké jsou země. Třicet stránek za minutu z jedné adresy je práh, který se člověka listujícího katalogem nedotkne:

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

Klíčové je, který protokol je uveden v logpath. Pokud pod masku spadne protokol samotného řídicího panelu nebo administrace, zablokujete sami sebe: jediná jeho stránka za sebou táhne desítku požadavků na styly a skripty a třicet se nasbírá na dvě kliknutí. Proto se panelu dává vlastní soubor protokolu, který masce jailu neodpovídá, a statickým souborům dlouhá doba platnosti v mezipaměti, aby je prohlížeč nežádal znovu při každém přechodu. Příznak, pokud k tomu přece jen došlo: HTML dorazí, vzhled ne, stránka visí. Zrušení blokace:

sudo fail2ban-client set http-flood unbanip 203.0.113.10

Krok 4. Ochránit to, co se nesmí odříznout

Než blokace zapnete, zapište výjimky — jinak pod ně jako první spadne to potřebné:

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

Co v tomto řádku musí být bezpodmínečně a proč:

  • Vaše vlastní adresa nebo podsíť kanceláře. Nejčastější příčinou ztráty přístupu k serveru je vlastní pravidlo, nikoli útok;
  • Rozsah 66.249.64.0/19. Vyhledávací robot Google se pozná podle User-Agenta, ale ta jeho část, která provádí JavaScript, přichází jako obyčejný Chrome/Linux a nepředstavuje se. Jakékoli pravidlo typu „blokovat provoz z datových center“ zasáhne právě ji, načež stránky tiše vypadnou z indexu. Podezřelou adresu lze ověřit zpětným dotazem: dig -x 66.249.66.1 +short má vrátit jméno v zóně googlebot.com;
  • Adresy platebních oznámení. Webhooky platebních systémů přicházejí ze serverů AWS a Azure. Pokud tyto cloudy uzavřete celé, potvrzení plateb přestanou docházet, a dozvíte se to ve chvíli, kdy zákazník napíše, že peníze odešly, ale přístup nemá. Rozsahy se berou z dokumentace vašeho poskytovatele plateb.

Krok 5. Je-li blokace přece jen nutná — blokujte podsíť, ne zemi

Trvalé zahuštění z jediné sítě, které drží celé dny a provází je stejnorodé požadavky, je jeden vykonavatel procházející seznam. Takový případ se blokuje bodově a na čas:

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

Druhým příkazem si zapamatujte číslo pravidla: blokaci bude třeba zrušit právě přes ně, sudo ufw delete <číslo>. Domluvte se sami se sebou na lhůtě — třeba měsíc — a zrušení si zapište do kalendáře. Pravidla nastavená „navždy“ se po roce promění v seznam, kterého se nikdo neodváží dotknout, protože si nikdo nepamatuje, za co se ty adresy do něj dostaly.

Kterou podsíť blokovat, zjistíte podle adresy z prvního kroku: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.

Co se po těchto pěti krocích mění

Skenery se odřezávají podle záměru, a ne podle původu, a chytají se při prvním požadavku. Roboti narazí na omezení tempa. Vyhledávací robot a platební oznámení dál procházejí. Jediná blokace, která zůstala široká, je bodová, se známou lhůtou a srozumitelným důvodem.

Mapa přitom nikam nemizí, ale její role se mění: není tu od toho, aby zavírala země, ale aby zahuštění vůbec zaznamenala a porovnala je s tím, co bylo před týdnem. K tomu je potřeba historie, a ne snímek aktuálního dne. Jak taková mapa vypadá vedle protokolu blokací a seznamu otevřených portů, ukazují ukázkové stránky níže.