UFW IPv6 Sicherheitslücke auf dem VPS schließen
UFW schützt oft nur IPv4. Erfahren Sie, warum Dienste über IPv6 trotz Firewall erreichbar bleiben und wie Sie die Lücke auf Ubuntu 24.04 sicher schließen.
Die IPv6-Firewall-Falle in einem Satz
Ihre Firewall schützt IPv4. Ihr VPS besitzt mit an Sicherheit grenzender Wahrscheinlichkeit auch eine öffentliche IPv6-Adresse, und viele Dienste lauschen standardmäßig darauf. Wenn Ihre Firewall nur IPv4 abdeckt oder Sie eine Cloud-Firewall nutzen, die nur IPv4 filtert, ist jeder dieser Dienste über IPv6 aus dem gesamten Internet erreichbar, während Ihre IPv4-Seite abgesichert scheint. Sie testen einen Port mit curl, sehen eine abgelehnte Verbindung und fühlen sich sicher. Ein Angreifer verbindet sich über IPv6 mit demselben Port und dringt ein.
Diese Anleitung zeigt, wie diese Sicherheitslücke auf einem Standard-Ubuntu 24.04 VPS entsteht, wie Sie genau sehen, was Sie exponieren, und wie Sie diese Lücke schließen. UFW ist hier nicht die Ursache. Bei einer modernen Ubuntu-Installation verwaltet UFW IPv6 bereits automatisch. Die Sicherheitslücke entsteht durch die umgebenden Schichten und durch Dienste, von denen Sie nicht wussten, dass sie lauschen.
Warum Ihr VPS standardmäßig IPv6 verwendet
Fast jeder heutige VPS wird mit einer öffentlichen IPv6-Adresse ausgeliefert, oft sogar mit einem kompletten /64, zusätzlich zu seiner IPv4-Adresse. Prüfen Sie Ihre Konfiguration:
ip -6 addr show scope global2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
inet6 2001:db8:2a::1/64 scope globalDiese 2001:db8:2a::1 ist von überall im Internet aus erreichbar, genau wie Ihre IPv4-Adresse. Prüfen Sie nun, welche Dienste lauschen:
sudo ss -tlnpState Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 [::]:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:8080 docker-proxyLesen Sie die Spalte Local Address genau. 0.0.0.0:22 bedeutet „auf jeder IPv4-Adresse lauschen“. [::]:22 bedeutet „auf jeder IPv6-Adresse lauschen“. 127.0.0.1:5432 ist an das Loopback-Interface gebunden und ist nicht öffentlich erreichbar; die Postgres-Zeile ist also sicher. Die beiden [::]-Zeilen antworten auf Anfragen aus dem gesamten Internet über IPv6, und die docker-proxy-Zeile ist die Art, die man nach dem Start oft vergisst.
Die meisten Daemons binden standardmäßig an ::, da unter Linux ein ::-Socket normalerweise auch IPv4 akzeptiert. Die Standardeinstellung eines frischen Servers ist daher „auf beiden Stacks überall antworten“. Ihre Firewall ist das einzige Hindernis; deshalb ist eine Firewall, die nur einen Stack betrachtet, ein ernsthaftes Problem.
Woher die IPv6-Lücke tatsächlich entsteht
Es gibt vier häufige Ursachen. Auf einem System können eine oder mehrere dieser Ursachen gleichzeitig vorliegen.
1. Eine Cloud-Firewall, die nur IPv4 filtert. Viele Firewalls von Providern und Security-Group-Produkte wurden für IPv4 entwickelt. Sie ignorieren IPv6 entweder oder benötigen separate IPv6-Regeln, die manuell hinzugefügt werden müssen. Wenn die einzige Firewall das Dashboard des Providers ist und diese kein IPv6 abdeckt, sind Ihre [::] Dienste offen, unabhängig von den Einstellungen für Port 22 unter IPv4. Lesen Sie die Firewall-Dokumentation Ihres Providers und suchen Sie gezielt nach dem Begriff IPv6.
2. Manuelle iptables ohne ip6tables. Der Befehl iptables wirkt nur auf die IPv4-Tabellen. IPv6 verwendet einen komplett separaten Befehl, ip6tables, mit eigenen Regeln. Wenn Sie ein Firewall-Skript mit iptables -A INPUT ...-Zeilen erstellt haben, aber die entsprechenden ip6tables-Regeln fehlen, ist Ihre IPv6-Firewall leer. Eine leere INPUT-Chain mit der Standard-Policy ACCEPT erlaubt jeglichen Zugriff:
sudo ip6tables -L INPUT -nChain INPUT (policy ACCEPT)
target prot opt source destinationDiese Ausgabe zeigt die gesamte Problematik auf einem Bildschirm. IPv4 wird gefiltert, IPv6 akzeptiert alle Verbindungen.
3. Docker-Port-Publishing umgeht die Firewall. Wenn Sie docker run -p 8080:80 ausführen, fügt Docker eigene Regeln vor den UFW-Regeln ein. Ein freigegebener Port ist somit erreichbar, selbst wenn ufw status den Port blockiert. Bei modernem Docker gilt dies auch für IPv6. Warum Docker UFW umgeht und wie man Container-Ports korrekt filtert erklärt den Mechanismus und die Lösungen. Weitere Informationen zur Deklaration dieser Ports finden Sie unter Grundlagen von Docker Compose auf einem VPS.
4. UFW mit deaktiviertem IPv6. UFW unterstützt IPv6, aber nur wenn dies explizit konfiguriert ist. Prüfen Sie die Einstellung:
grep IPV6 /etc/default/ufwModerne Ubuntu-Versionen nutzen IPV6=yes, sodass UFW jede Regel auf beide Protokollstapel anwendet. Wenn Sie IPV6=no sehen (aus einem alten Image oder einer veralteten Anleitung), sind alle Ihre UFW-Regeln nur für IPv4 gültig und IPv6 bleibt ungeschützt.
Prüfen Sie genau, was Sie exponieren
Raten Sie nicht. Messen Sie von außen. Listen Sie zuerst Ihre Listener auf und notieren Sie jeden Eintrag, der an :: gebunden ist:
sudo ss -tlnp | grep '::'Verbinden Sie sich dann von einem anderen Rechner mit der öffentlichen IPv6-Adresse des Servers und versuchen Sie den Zugriff auf einen Port, von dem Sie glauben, dass er geschlossen ist:
curl -6 -v http://[2001:db8:2a::1]:8080/Wenn eine Webseite oder ein Banner zurückgegeben wird, ist der Port über IPv6 offen. Ein geschlossener Port liefert Connection refused oder einen Timeout. Um ein vollständiges Bild zu erhalten, scannen Sie die IPv6-Adresse von außerhalb des Servers mit nmap:
nmap -6 2001:db8:2a::1Jeder Port, den nmap über IPv6 als offen meldet, ist ein Port, der über das gesamte Internet erreichbar ist, unabhängig von den Ergebnissen Ihres IPv4-Scans. Ein direkter Vergleich der IPv4- und IPv6-Scans ist der schnellste Weg, um Lücken zu finden: Alles, was auf -6 offen, aber auf IPv4 geschlossen ist, ist ein Dienst, der von Ihrer Firewall nicht abgedeckt wird.
Schließen Sie die Sicherheitslücke
Konfigurieren Sie UFW für beide Stacks und setzen Sie die Standardrichtlinie auf deny. Bestätigen Sie die Umstellung, setzen Sie eine Default-Deny-Policy für eingehende Verbindungen und erlauben Sie nur das Nötigste:
sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verboseFalls UFW bereits aktiv war, als Sie IPV6=yes geändert haben, tritt die Änderung erst nach der Ausführung von sudo ufw reload in Kraft.
ufw status listet jede Regel doppelt auf: einmal im Klartext und einmal mit einem (v6)-Suffix. Wenn Sie die (v6)-Zeilen sehen, filtert UFW IPv6:
22/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)Falls Sie iptables manuell verwalten, spiegeln Sie jede Regel in ip6tables, oder wechseln Sie zu nftables. Die inet-Tabellen von nftables decken IPv4 und IPv6 an einem Ort ab und verhindern diese Fehlerklasse. Eine einzelne nftables inet-Filtertabelle ist die sauberste Lösung, wenn Sie Regeln selbst schreiben.
Binden Sie Dienste, die nicht öffentlich erreichbar sein sollen, an das Loopback-Interface. Eine Datenbank, ein Admin-Panel oder ein Metrik-Endpunkt benötigt selten eine öffentliche Adresse. Binden Sie diese an 127.0.0.1 und ::1, damit der Dienst gar nicht erst auf einer routbaren Adresse lauscht. Setzen Sie für Postgres listen_addresses = 'localhost'. Binden Sie einen App-Server an 127.0.0.1 und schalten Sie einen Reverse Proxy davor. Das Schließen des Listen-Ports ist effektiver als eine Firewall-Regel, da der Dienst dann gar nicht erst erreichbar ist.
Verlassen Sie sich nicht auf UFW zum Schutz der von Docker veröffentlichten Ports. Veröffentlichen Sie Container-Ports an eine spezifische Adresse statt an alle Interfaces, zum Beispiel -p 127.0.0.1:8080:80. So ist der Port nur vom Host und von den Diensten aus erreichbar, für die Sie explizit ein Proxying eingerichtet haben. Wenn ein Container zwingend öffentlich erreichbar sein muss, platzieren Sie ihn hinter einen Traefik Reverse Proxy und veröffentlichen Sie nur den Proxy, nicht jede einzelne Applikation.
Fügen Sie IPv6-Regeln in der Firewall Ihres Providers hinzu, oder akzeptieren Sie, dass dies nicht Ihre Firewall für IPv6 ist, und lassen Sie stattdessen UFW oder nftables auf dem Host diese Aufgabe übernehmen.
Überprüfen Sie, ob die Verbindung tatsächlich geschlossen ist
Führen Sie nach Ihren Änderungen denselben externen Test erneut aus:
curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1Der Port, der zuvor geantwortet hat, sollte nun die Verbindung verweigern oder einen Timeout verursachen. nmap sollte den Port als filtered oder closed melden. Falls ein Port weiterhin offen ist, prüfen Sie die vier oben genannten Ursachen: Ein Dienst ist weiterhin an :: gebunden, ohne dass eine Regel aktiv ist; eine Docker-Regel steht vor UFW; oder eine Firewall des Providers erkennt IPv6 überhaupt nicht.
Es ist noch sicherer, sensible Dienste vollständig vom öffentlichen Internet zu trennen. Platzieren Sie SSH und Admin-Panels hinter einem WireGuard VPN und sichern Sie die Ports per Firewall ab, sodass sie nur über den Tunnel antworten. Damit entfällt die Problematik der IPv6-Exposition für diese Dienste. Um Brute-Force-Scans auf öffentlich erreichbaren Diensten entgegenzuwirken, sollten Sie Fail2ban vor SSH zusätzlich zu einer Default-Deny-Firewall einsetzen.
Falls Sie mit Ports noch nicht vertraut sind, lesen Sie zuerst was Ports sind und wie Dienste lauschen.
FAQ
Blockiert UFW IPv6 standardmäßig?
Bei einer aktuellen Ubuntu 24.04 Installation ja. UFW liest IPV6=yes aus /etc/default/ufw und wendet jede Regel auf IPv4 und IPv6 an. ufw status zeigt die IPv6-Regeln mit einem (v6) Suffix an. Probleme entstehen bei IPV6=no (aus einem alten Image oder Tutorial), wenn Sie sich auf eine Provider-Firewall verlassen, die nur IPv4 filtert, oder wenn Docker einen Port außerhalb von UFW veröffentlicht. Prüfen Sie die Einstellung mit grep IPV6 /etc/default/ufw.
Wie überprüfe ich, welche Dienste mein VPS über IPv6 exponieren?
Führen Sie sudo ss -tlnp aus und notieren Sie jeden Listener, dessen lokale Adresse mit [::] beginnt. Dies bedeutet, dass der Dienst auf jeder IPv6-Schnittstelle antwortet. Testen Sie dann von einem anderen Rechner aus die öffentliche IPv6-Adresse des Servers direkt mit curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/ oder scannen Sie diese mit nmap -6 YOUR:IPV6::ADDR. Jeder Port, der beim IPv6-Scan offen, aber bei IPv4 geschlossen ist, stellt eine Sicherheitslücke dar.
Warum ist der Port meines Docker-Containers erreichbar, obwohl UFW ihn blockiert?
Docker fügt eigene Firewall-Regeln vor den UFW-Regeln ein, wenn Sie einen Port mit -p veröffentlichen. Der veröffentlichte Port ist somit erreichbar, obwohl ufw status ihn als verweigert listet. Dies geschieht bei IPv4 und ebenfalls bei IPv6, wenn die IPv6-Unterstützung von Docker aktiviert ist. Veröffentlichen Sie den Port nur für eine spezifische Adresse wie -p 127.0.0.1:8080:80 oder stellen Sie den Container hinter einen Reverse Proxy und veröffentlichen Sie nur den Proxy.
Benötige ich noch eine IPv6-Firewall, wenn meine IPv4-Firewall sicher ist?
Ja. IPv4 und IPv6 sind separate Netzwerk-Stacks mit separaten Firewall-Regeln. Ein perfekter Satz von IPv4-Regeln hat keine Auswirkung auf den IPv6-Verkehr. Wenn Ihr VPS eine öffentliche IPv6-Adresse hat (was fast immer der Fall ist), bleibt jeder Dienst, der auf :: lauscht, über IPv6 erreichbar, bis eine IPv6-Firewall-Regel oder eine Loopback-Bindung dies verhindert.
Wie konfiguriere ich einen Dienst so, dass er nur auf IPv4 oder nur auf localhost lauscht?
Legen Sie die Bind-Adresse des Dienstes in dessen eigener Konfiguration fest. Binden Sie an 127.0.0.1 für nur IPv4-Loopback oder an 0.0.0.0 für alle IPv4-Adressen ohne IPv6-Listener. Postgres verwendet listen_addresses, SSH verwendet ListenAddress und die meisten App-Server bieten ein Host- oder Bind-Flag an. Bestätigen Sie das Ergebnis mit sudo ss -tlnp und prüfen Sie, ob Local Address [::] nicht mehr anzeigt.