Na mapie ataków widnieje gęsta plama nad jednym krajem i sama narzuca się reguła „zablokować go w całości”. Nie da ona prawie nic: zmiana kraju wyjścia zajmuje napastnikowi kilka minut, a pod blokadę trafią twoi właśni odwiedzający i ty sam w podróży. Co gorsza, widoczny robot przychodzący z jednej chmury po blokadzie przeniesie się na adresy domowe i przestanie być odróżnialny od ludzi.

Poniżej jest pięć kroków, które na tym samym serwerze naprawdę dają wynik: odciąć skanery, ograniczyć tempo, nie odciąć tego, co potrzebne, a jeśli blokada okaże się konieczna — zablokować prawidłowo. Wszystko można sprawdzić i ustawić podczas jednego podejścia.

Krok 1. Zobaczyć, kto rzeczywiście tworzy plamę

Najpierw znajdź dziennik żądań. Na serwerze z kilkoma witrynami access.log bywa pusty, a wpisy trafiają do dziennika konkretnego hosta wirtualnego:

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

We wszystkich dalszych komendach podstawia się plik, który znalazł się na górze tej listy. Najpierw adresy prowadzące w ciągu doby, potem to, o co dokładnie prosi ten z góry:

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

Druga komenda odpowiada na główne pytanie. Jeśli w wyniku są dziesiątki różnych stron twojej witryny — to zbieracz treści: jest nieszkodliwy i wystarczy nie liczyć go jako odwiedzającego. Jeśli są tam /wp-login.php, /.env, /phpmyadmin i inne rzeczy, których nie masz — to skaner, a nim zajmuje się krok 2. Dla nginx dzienniki leżą w /var/log/nginx/, pola są te same.

Krok 2. Jail na żądania do tego, czego nie masz

Ścieżki żądania nie da się podrobić — ona sama jest zamiarem, w odróżnieniu od adresu i 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

Tutaj maxretry = 1 jest uzasadnione: przypadkowych wejść do cudzego panelu administracyjnego nie ma. Zastosować i upewnić się, że filtr wyłapuje wpisy w twoim dzienniku:

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. Ograniczyć tempo

Skaner i robot zdradzają się szybkością, niezależnie od tego, z jakiego są kraju. Trzydzieści stron na minutę z jednego adresu to próg, który nie dotyka człowieka przeglądającego katalog:

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

Kluczowe jest to, który dziennik został wskazany w logpath. Jeśli pod maskę trafi dziennik samego panelu zarządzania albo panelu administracyjnego, zablokujesz siebie: jedna jego strona ciągnie za sobą dziesiątki żądań do styli i skryptów, a trzydzieści zbiera się w dwóch kliknięciach. Dlatego panelowi daje się osobny plik dziennika, który nie pasuje do maski jaila, a plikom statycznym — długi czas przechowywania w pamięci podręcznej, żeby przeglądarka nie prosiła o nie przy każdym przejściu. Objaw, jeśli jednak się to stało: HTML przychodzi, oprawy nie ma, strona wisi. Zdjęcie blokady:

sudo fail2ban-client set http-flood unbanip 203.0.113.10

Krok 4. Ochronić to, czego nie wolno odciąć

Przed włączeniem blokad wpisz wyjątki — inaczej jako pierwsze trafi pod nie to, co potrzebne:

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

Co koniecznie musi być w tej linii i dlaczego:

  • Twój własny adres albo podsieć biura. Najczęstszą przyczyną utraty dostępu do serwera jest własna reguła, a nie atak;
  • Zakres 66.249.64.0/19. Robot wyszukiwarki Google rozpoznaje się po User-Agencie, ale ta jego część, która wykonuje JavaScript, przychodzi jako zwykły Chrome/Linux i nie przedstawia się. Każda reguła w stylu „blokować ruch z centrów danych” uderza właśnie w nią, po czym strony cicho wypadają z indeksu. Podejrzany adres można sprawdzić zapytaniem odwrotnym: dig -x 66.249.66.1 +short powinno zwrócić nazwę w strefie googlebot.com;
  • Adresy powiadomień o płatnościach. Webhooki systemów płatniczych przychodzą z serwerów AWS i Azure. Jeśli zamkniesz te chmury w całości, potwierdzenia płatności przestaną dochodzić, a dowiesz się o tym wtedy, gdy klient napisze, że pieniądze zostały pobrane, a dostępu nie ma. Zakresy bierze się z dokumentacji twojego dostawcy płatności.

Krok 5. Jeśli blokada jest naprawdę potrzebna — blokuj podsieć, a nie kraj

Trwałe zgęszczenie z jednej sieci, które utrzymuje się całymi dniami i idzie w parze z jednakowymi żądaniami, to jeden wykonawca idący po liście. Taki przypadek blokuje się punktowo i na czas:

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

Drugą komendą zapamiętaj numer reguły: blokadę trzeba będzie zdjąć właśnie przez niego, sudo ufw delete <numer>. Umów się z sobą na termin — na przykład miesiąc — i wpisz zdjęcie blokady do kalendarza. Reguły ustawione „na zawsze” po roku zamieniają się w listę, której nikt nie ma odwagi tknąć, bo nikt nie pamięta, za co te adresy się tam znalazły.

Jaką podsieć zablokować, można ustalić po adresie z pierwszego kroku: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.

Co zmienia się po tych pięciu krokach

Skanery są odcinane według zamiaru, a nie pochodzenia, i wyłapywane przy pierwszym żądaniu. Roboty trafiają na ograniczenie tempa. Robot wyszukiwarki i powiadomienia o płatnościach dalej przechodzą. Jedyna blokada, która została szeroka, jest punktowa, ze znanym terminem i zrozumiałym powodem.

Mapa przy tym nie znika, ale jej rola się zmienia: jest potrzebna nie do zamykania krajów, a do tego, by samo zgęszczenie zauważyć i porównać z tym, co było tydzień temu. Do tego potrzebna jest historia, a nie zdjęcie bieżącej doby. Jak wygląda taka mapa razem z dziennikiem blokad i listą otwartych portów, pokazują strony demonstracyjne poniżej.