Rate-Limiting mit der ufw
ufw steht für uncomplicated firewall – prinzipiell ein sehr guter Ansatz, für manche Anwendungszwecke ist die ufw leider aber doch ein wenig zu eingeschränkt.
Im vorliegenden Fall wünschte ein Kunde ein einfaches Rate Limiting auf dem HTTP(S)-Port seines Servers, was durch ein wenig Konfiguration per Hand aber am Ende auch kein Problem war.
Einfaches Limiting mit vorgegebenen Grenzwerten
Ein simples Limiting mit vorgegebenen Grenzwerten ist schnell umgesetzt. Um die Anfragen auf Port 80 und 443 (hier wird der Webserver NGINX benutzt) zu begrenzen, genügen die folgenden Befehle:
ufw limit "Nginx HTTP"
ufw limit "Nginx HTTPS"
Nun werden Anfragen einer IP-Adresse abgelehnt, wenn 6 oder mehr Verbindungen in den letzten 30 Sekunden davon ausgehend aufgebaut wurden. Das ergibt für z.B. SSH eventuell Sinn, für einen Webserver allerdings eher weniger – wie also können wir die Grenzwerte anpassen? „Einfach so“ leider nicht, wir müssen tiefer graben und uns vom uncomplicated der Firewall ein wenig verabschieden.
Rate Limit mit eigenen Grenzwerten
Um Grenzwerte festzulegen, die für einen Webserver besser passen, passen wir die Datei /etc/ufw/before.rules an und fügen unter # End Required Lines
folgende Zeilen ein:
# CUSTOM UFW
:ufw-http - [0:0]
:ufw-http-logdrop - [0:0]
# END CUSTOM
Weiter unten vor der Zeile COMMIT
fügen wir folgendes ein:
### Start HTTP ###
# Enter rule
-A ufw-before-input -p tcp --dport 80 -j ufw-http
-A ufw-before-input -p tcp --dport 443 -j ufw-http
# Limit connections per Class C
-A ufw-http -p tcp --syn -m connlimit --connlimit-above 50 --connlimit-mask 24 -j ufw-http-logdrop
# Limit connections per IP
-A ufw-http -m state --state NEW -m recent --name conn_per_ip --set
-A ufw-http -m state --state NEW -m recent --name conn_per_ip --update --seconds 10 --hitcount 45 -j ufw-http-logdrop
# DDOS
-A ufw-http -m hashlimit --hashlimit 100/sec --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-name nginx_DDOS --hashlimit-htable-expire 30000 --hashlimit-htable-max 65535 -j ACCEPT
-A ufw-http -j LOG --log-prefix "[UFW DDOS DROP]"
-A ufw-http -j DROP
# Finally accept
-A ufw-http -j ACCEPT
# Log
-A ufw-http-logdrop -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW HTTP DROP] "
-A ufw-http-logdrop -j DROP
Ich gehe kurz auf die einzelnen Regeln ein…
Limit connections per Class C
Wir beginnen Anfragen aus einem Class C-Netz zu blockieren, wenn mehr als 50 Verbindungen aus dem Netz gleichzeitig geöffnet sind. Die Werte können natürlich angepasst werden, passen aber erfahrungsgemäß ganz gut für einfache Webserver. Dieses Limit blockiert simple Angriffsversuche ganz gut.
Limit connections per IP
Die Verbindungen pro IP werden blockiert, wenn eine IP-Adresse mehr als 45 Anfragen pro 10 Sekunden stellt.
DDOS
Die Regel ist ein wenig speziell und muss entsprechend getestet und angepasst werden. Eine gute, ausführliche Erklärung der Optionen findet sich z.B. hier.
Nachdem wir nun alle Regeln gesetzt und (hoffentlich) verstanden haben, müssen wir die Regeln nur noch neu laden.
Beobachten, was die Firewall nun blockt, können wir im Log /var/log/ufw.log.
Gerne kann ich Ihnen das oben genannte oder weitere, komplexere Setups günstig einrichten – kontaktieren Sie mich für eine Einschätzung und ein unverbindliches Angebot.