Nftables Webserver Beispiel
Zur Navigation springen
Zur Suche springen
#!/usr/sbin/nft -f
#
# Gehärtete nftables-Config für einen Webserver
# Änderungen ggü. Ausgangsversion:
# - ct state invalid wird explizit verworfen (nicht nur implizit durch policy drop)
# - Rate-Limiting gegen ICMP-Flood
# - SYN-Flood-Schutz für neue TCP-Verbindungen
# - Logging mit Rate-Limit (statt nur "counter drop")
# - Output-Chain: policy drop statt accept, nur benötigter ausgehender Traffic erlaubt
# - Webserver-Prozess (UID www-data) darf grundsätzlich KEINE ausgehenden
# Verbindungen aufbauen -> verhindert Reverse Shells, Malware-Downloads,
# C2-Callbacks im Falle einer Kompromittierung (z.B. via Webshell)
#
# IPv6 wird bewusst nicht behandelt - da policy drop gilt, wird jeglicher
# IPv6-Traffic ohnehin verworfen (Default-Policy greift auch ohne explizite
# ip6-Regeln, da die Tabelle "inet" ist).
#
# SSH (Port 22) wird bewusst NICHT weiter eingeschränkt (Source-IP-Filter,
# Rate-Limit) - das wird laut Vorgabe separat/anders gehandhabt.
flush ruleset
table inet filter {
# UID des Webserver-Prozesses - ggf. anpassen (z.B. nginx: 33, oft auch
# eigener User statt www-data; mit `id www-data` bzw. `ps aux | grep nginx`
# prüfen, welcher User den Webserver-Prozess tatsächlich fährt)
define WEBSERVER_UID = 33
chain input {
type filter hook input priority filter; policy drop;
# Loopback immer erlauben
iif lo accept
# Ungültige Pakete explizit verwerfen (nicht erst der Default-Policy
# überlassen - so lässt sich das auch gezielt loggen)
ct state invalid counter drop
# Bestehende/verwandte Verbindungen erlauben
ct state established,related accept
# SSH - unverändert offen, wird separat abgesichert
ct state new tcp dport 22 accept
# HTTP/HTTPS mit SYN-Flood-Schutz: neue Verbindungen pro Quelle begrenzen.
# Bewusst NUR diese eine Regel - established/related ist bereits weiter
# oben abgedeckt. Eine zusätzliche ungefilterte "tcp dport {80,443} accept"
# würde das Rate-Limit aushebeln, da überschüssige Pakete sonst einfach
# zur nächsten Regel weiterlaufen und dort ungebremst akzeptiert würden.
ct state new tcp dport { 80, 443 } limit rate 50/second burst 20 packets accept
# ICMP für Diagnose, aber mit Rate-Limit gegen Ping-Flood
ct state new ip protocol icmp icmp type echo-request limit rate 10/second accept
ct state new ip protocol icmp accept
# Alles andere: mit Rate-limitiertem Logging verwerfen
limit rate 5/minute log prefix "nft-input-drop: " counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy drop;
# Loopback
oif lo accept
# Bestehende/verwandte Verbindungen (Antworten auf eingehende Requests,
# z.B. HTTP-Responses) erlauben - aber s. u., für WEBSERVER_UID gesperrt
ct state established,related accept
# --- Webserver-Prozess: keinerlei neue ausgehende Verbindungen ---
# Das muss VOR den allgemeinen "erlauben"-Regeln stehen, damit es
# nicht durch established,related o.ä. unterlaufen wird. Auch
# established/related wird für diese UID hier schon effektiv verhindert,
# da der Webserver ja nie eine ausgehende Verbindung initiieren darf,
# aus der ein "established" Zustand entstehen könnte.
meta skuid $WEBSERVER_UID counter log prefix "nft-webserver-egress-blocked: " drop
# Ab hier: regulärer System-Traffic (läuft NICHT unter WEBSERVER_UID)
# DNS-Auflösung
ct state new udp dport 53 accept
ct state new tcp dport 53 accept
# NTP für Zeitsynchronisation
ct state new udp dport 123 accept
# HTTPS für Paket-Updates, externe API-Calls des Systems etc.
ct state new tcp dport 443 accept
# SSH-Verbindungen vom System selbst nach außen (z.B. für Admin-Zwecke),
# bei Bedarf entfernen, falls nicht benötigt
ct state new tcp dport 22 accept
# ICMP für Diagnosezwecke (ping, traceroute vom Host aus)
ct state new ip protocol icmp accept
# Alles andere ausgehende: loggen und verwerfen
limit rate 5/minute log prefix "nft-output-drop: " counter drop
}
}