Daemon jest konfigurowany w całości przez zmienne środowiskowe i dwa pliki na dysku. Bez konieczności zmian w kodzie, aby dostosować zachowanie.

Zmienne środowiskowe

ZmiennaTypDefaultCel
ABUSIVE_FAMILYv4 / v6 / anyanyOgraniczyć matching do rodziny IP.
ABUSIVE_MIN_HITSinteger ≥ 13Trafienia ze źródła, zanim IP zostanie zapisane na blocklistę.
ABUSIVE_SCOPElista oddzielona przecinkamirequest,uaKtóre pola loga są oceniane. Dozwolone: request, ua, referrer.
ABUSIVE_REFERRER_DOMAINSlista whitespace/przecinek(puste)Dozwolone hosty referrer. Istotne tylko, gdy referrer w ABUSIVE_SCOPE.
ABUSIVE_SYSLOG_TAGstringabusive_http_watchTag programu syslog.
ABUSIVE_SYSLOG_FACILITYstringdaemonFacility syslog. local0local7 dla własnych routingów.
ABUSIVE_SYSLOG_PRIOinfo / notice / warn / errnoticePriorytet syslog dla eventów added.
ABUSIVE_DEBUG0 / 10Verbose-stderr-trace każdej linii. Sensowne tylko do scopingu.

Uwagi

  • ABUSIVE_MIN_HITS — Ustawienie na 1 blokuje przy pierwszym trafieniu. Agresywniej, ale podnosi ryzyko false-positive przez sondy one-shot z benignych cloud-IP, które później pojawiają się regularnie. Default 3 to dobry kompromis.
  • ABUSIVE_SCOPEreferrer jest domyślnie wyłączony, ponieważ złośliwy referrer przez drive-by mógłby wepchnąć IP twojego odwiedzającego na blocklistę. Włączać tylko, gdy ABUSIVE_REFERRER_DOMAINS jest ustawiony jako ścisła allowlist.
  • ABUSIVE_FAMILY — Przydatne, gdy chce się odzwierciedlić daemona przez dwa procesy: jeden dla IPv4, jeden dla IPv6, każdy z własnym plikiem blocklisty.

Zestaw tokenów

Zestaw regex wykrywania jest na sztywno wpisany w skrypcie (@TOKENS) i pokrywa osiem klas ataków — eksploatacja PHP, sondy WordPress, path-traversal, ścieżki wrażliwe, próby RCE/CGI, SQL-injection, sondy login-loop i null-byte-injection.

Aby dostosować zestaw:

  1. Otworzyć skrypt.
  2. Dostosować tablicę @TOKENS — dodać lub usunąć wzorce, jeśli występują false-positives.
  3. Zrestartować daemona.

Zestaw jest celowo konserwatywny. Dodawanie tokenów typu /admin, /login czy phpmyadmin bez scopingu prowadzi do false-positives na legalnym ruchu.

Plik whitelist

Ścieżka: /etc/abusive_http_whitelist

Jeden wpis na linię. Wspierane są trzy formaty:

# komentarze dozwolone
203.0.113.42                    # pojedyncze IPv4
2001:db8::abcd                  # pojedyncze IPv6 (pełne lub skrócone)
203.0.113.0/24                  # IPv4 CIDR
2001:db8::/32                   # IPv6 CIDR

IP z whitelist są w całości pomijane — nie zwiększają licznika trafień i nigdy nie lądują na blockliście, nawet jeśli ich requesty trafiają w każdy token z zestawu.

Whitelisty używać dla:

  • Publicznych IP biura i VPN (operatorzy, którzy nieumyślnie odpalają skanery).
  • Dokumentowanych legalnych ranges crawlerów wyszukiwarek (Google, Bing). Najpierw przetestować — rzadko konieczne, bo ich requesty nie trafiają w tokeny ataków.
  • Serwisów monitoringowych, które celowo odpytują /wp-login.php.

Plik blocklisty

Ścieżka: /var/www/run/abusive_http_hosts

Format: jedno IP na linię, bez komentarzy, bez nagłówków, bez duplikatów. Daemon zapewnia deduplikację przez hash in-memory i flock(LOCK_EX) przy zapisie.

Plik jest w czasie działania append-only — stare wpisy nigdy nie są usuwane przez daemona. Do sprzątania (np. wygaszanie wpisów po 30 dniach) używać rotacji zewnętrznej:

# W cron dziennym
mv /var/www/run/abusive_http_hosts /var/www/run/abusive_http_hosts.old
touch /var/www/run/abusive_http_hosts
chown _www:_www /var/www/run/abusive_http_hosts
doas rcctl restart abusive_http_watch

To wymusza na daemonie odbudowę stanu in-memory z pustego pliku. Firewall ładuje nową (pustą) blocklistę przy następnym ticku crona.

Konsumpcja przez firewall

Format pliku blocklisty jest celowo płaski, aby każda warstwa mogła go skonsumować. Częste integracje:

OpenBSD pf

table <abusive> persist file "/var/www/run/abusive_http_hosts"
block in quick on egress from <abusive>

Przeładować tabelę:

pfctl -t abusive -T replace -f /var/www/run/abusive_http_hosts

Linux nftables

table inet filter {
  set abusive_v4 {
    type ipv4_addr
    elements = { ... }
  }
  chain input {
    ip saddr @abusive_v4 drop
  }
}

Set przeładowywany przez helper z pliku:

nft 'flush set inet filter abusive_v4'
awk '/^[0-9]/ {print}' /var/www/run/abusive_http_hosts | \
  xargs -I{} nft 'add element inet filter abusive_v4 { {} }'

Apache

<RequireAll>
  Require all granted
  Require not ip 203.0.113.0/24
  # … jeden Require not ip per wpis blocklisty
</RequireAll>

Generowane przez templater (m4, sed) z pliku blocklisty na cronie. Reaguje wolniej niż integracja firewallowa, ale działa, gdy nie kontrolujesz samej warstwy firewall.

nginx

geo $abusive {
  default 0;
  include /var/www/run/abusive_http_nginx.conf;
}
server {
  if ($abusive) { return 444; }
}

abusive_http_nginx.conf jest generowany przez template z pliku blocklisty.