Nftables Webserver Beispiel: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
(Die Seite wurde neu angelegt: „<pre> #!/usr/sbin/nft -f # Flush existing rules flush ruleset # Define the main table for filtering table inet filter { # Input chain - handles incoming tr…“) |
|||
| Zeile 1: | Zeile 1: | ||
<pre> | <pre> | ||
#!/usr/sbin/nft -f | #!/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 ICMP nicht pauschal erlaubt, sondern nur die für den Betrieb nötigen Typen | ||
| + | # | ||
| + | # 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 | ||
| + | tcp dport 22 accept | ||
| + | |||
| + | # HTTP/HTTPS mit SYN-Flood-Schutz: neue Verbindungen pro Quelle begrenzen | ||
| + | tcp dport { 80, 443 } ct state new limit rate 50/second burst 20 packets accept | ||
| + | tcp dport { 80, 443 } accept | ||
| + | |||
| + | # ICMP für Diagnose, aber mit Rate-Limit gegen Ping-Flood | ||
| + | ip protocol icmp icmp type echo-request limit rate 10/second accept | ||
| + | ip protocol icmp accept | ||
| + | |||
| + | # ICMPv6: nicht pauschal, sondern nur die für Betrieb/Neighbor Discovery | ||
| + | # nötigen Typen (bei IPv6 essenziell, sonst brechen NDP/SLAAC/PMTU) | ||
| + | ip6 nexthdr icmpv6 icmpv6 type { | ||
| + | destination-unreachable, | ||
| + | packet-too-big, | ||
| + | time-exceeded, | ||
| + | parameter-problem, | ||
| + | echo-request, | ||
| + | echo-reply, | ||
| + | nd-router-solicit, | ||
| + | nd-router-advert, | ||
| + | nd-neighbor-solicit, | ||
| + | nd-neighbor-advert | ||
| + | } 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 | ||
| + | udp dport 53 accept | ||
| + | tcp dport 53 accept | ||
| − | # | + | # NTP für Zeitsynchronisation |
| + | udp dport 123 accept | ||
| − | + | # HTTPS für Paket-Updates, externe API-Calls des Systems etc. | |
| − | # | + | 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 | |
| − | + | tcp dport 22 accept | |
| − | |||
| − | # | + | # ICMP für Diagnosezwecke (ping, traceroute vom Host aus) |
| − | + | ip protocol icmp accept | |
| − | + | ip6 nexthdr icmpv6 accept | |
| − | |||
| − | |||
| − | |||
| − | |||
| + | # Alles andere ausgehende: loggen und verwerfen | ||
| + | limit rate 5/minute log prefix "nft-output-drop: " counter drop | ||
| + | } | ||
} | } | ||
</pre> | </pre> | ||
Version vom 3. August 2026, 07:28 Uhr
#!/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 ICMP nicht pauschal erlaubt, sondern nur die für den Betrieb nötigen Typen
#
# 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
tcp dport 22 accept
# HTTP/HTTPS mit SYN-Flood-Schutz: neue Verbindungen pro Quelle begrenzen
tcp dport { 80, 443 } ct state new limit rate 50/second burst 20 packets accept
tcp dport { 80, 443 } accept
# ICMP für Diagnose, aber mit Rate-Limit gegen Ping-Flood
ip protocol icmp icmp type echo-request limit rate 10/second accept
ip protocol icmp accept
# ICMPv6: nicht pauschal, sondern nur die für Betrieb/Neighbor Discovery
# nötigen Typen (bei IPv6 essenziell, sonst brechen NDP/SLAAC/PMTU)
ip6 nexthdr icmpv6 icmpv6 type {
destination-unreachable,
packet-too-big,
time-exceeded,
parameter-problem,
echo-request,
echo-reply,
nd-router-solicit,
nd-router-advert,
nd-neighbor-solicit,
nd-neighbor-advert
} 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
udp dport 53 accept
tcp dport 53 accept
# NTP für Zeitsynchronisation
udp dport 123 accept
# HTTPS für Paket-Updates, externe API-Calls des Systems etc.
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
tcp dport 22 accept
# ICMP für Diagnosezwecke (ping, traceroute vom Host aus)
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# Alles andere ausgehende: loggen und verwerfen
limit rate 5/minute log prefix "nft-output-drop: " counter drop
}
}