Der häufigste Befund bei einer Prüfung von außen ist kein exotischer Dienst, sondern eine Maschine, die über IPv4 sauber gefiltert ist und über IPv6 offen steht. Der Grund ist banal: Regeln wurden mit iptables geschrieben, und iptables kennt kein IPv6.
Es entsteht ein Schutz, den man belegen kann, für die falsche Hälfte des Netzes. Scanner prüfen längst beide Familien, und ein Dienst, der auf [::] lauscht, ist über die AAAA-Adresse genauso erreichbar wie über die A-Adresse. Wer nur IPv4 misst, misst an der offenen Tür vorbei.
Erst nachsehen, was überhaupt hört#
# Getrennt nach Familie — die eckigen Klammern sind IPv6
sudo ss -tulpn | awk '{print $1, $5, $7}' | column -t
# Welche Adressen hat die Maschine?
ip -6 addr show scope global
ip -4 addr show scope global
Ein Dienst auf [::]:5432 ist von außen erreichbar, auch wenn 0.0.0.0:5432 nirgends auftaucht, viele Programme binden mit einem einzigen Socket beide Familien.
Eine Tabelle für beide Familien#
Der saubere Weg ist nftables mit der Familie inet: Eine Regel, beide Protokolle.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
# ICMP: bei IPv6 kein Komfort, sondern Voraussetzung
ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept
ip6 nexthdr icmpv6 icmpv6 type {
echo-request, destination-unreachable, packet-too-big, time-exceeded,
parameter-problem, nd-neighbor-solicit, nd-neighbor-advert,
nd-router-solicit, nd-router-advert
} accept
tcp dport { 22, 80, 443 } accept
}
chain forward { type filter hook forward priority 0; policy drop; }
chain output { type filter hook output priority 0; policy accept; }
}
sudo nft -f /etc/nftables.conf
sudo systemctl enable nftables
sudo nft list ruleset | head -30
Bei IPv4 kann man ICMP grob behandeln, ohne dass sofort etwas bricht. Bei IPv6 ist es Bestandteil des Protokolls: Ohne packet-too-big gibt es keine funktionierende Pfad-MTU-Erkennung, Verbindungen bauen sich auf und bleiben dann bei größeren Paketen stehen. Ohne Neighbor Discovery findet die Maschine ihre Nachbarn nicht. Das Fehlerbild ist heimtückisch: kleine Anfragen gehen, große hängen.
Wenn ufw im Einsatz ist#
ufw kann IPv6, aber nur wenn es eingeschaltet ist:
grep -i ipv6 /etc/default/ufw # erwartet: IPV6=yes
sudo ufw status verbose # zeigt Regeln je Familie mit (v6)
Steht dort IPV6=no, gelten sämtliche Regeln nur für IPv4, inklusive der Standardrichtlinie. Nach dem Umstellen ist ein sudo ufw disable && sudo ufw enable nötig.
Der Beleg kommt von außen#
Von einer anderen Maschine, die selbst IPv6 hat:
ZIEL=example.org
dig +short A "$ZIEL"; dig +short AAAA "$ZIEL"
nmap -Pn --top-ports 200 "$(dig +short A "$ZIEL" | head -1)"
nmap -Pn -6 --top-ports 200 "$(dig +short AAAA "$ZIEL" | head -1)"
Die beiden Ausgaben müssen sich decken. Tun sie das nicht, ist die Differenz genau das Loch.
Wer keine IPv6-Anbindung am Prüfrechner hat, prüft über eine kleine VM bei einem anderen Anbieter, ein Test „von innen“ beantwortet die Frage nicht, wie in Angriffsfläche von außen messen beschrieben.
Zwei Sonderfälle#
Docker. Ohne "ip6tables": true in /etc/docker/daemon.json gibt es für IPv6 überhaupt keine Docker-Regeln, veröffentlichte Ports sind dann ungefiltert erreichbar. Details in Docker umgeht deine Firewall.
Privacy Extensions und wechselnde Adressen. Wer Regeln auf einzelne IPv6-Adressen schreibt, sollte wissen, dass Clients ihre Adresse regelmäßig wechseln. Für Zugriffsbeschränkungen ist deshalb das Präfix (/64) die brauchbare Einheit, oder besser gleich ein Overlay-Netz statt einer Adressregel (WireGuard statt offener Ports).
Abschalten ist keine Lösung#
IPv6 zu deaktivieren wirkt wie die einfache Antwort und schafft neue Probleme: Manche Dienste erwarten es lokal, Anbieter vergeben teilweise nur noch IPv6 mit Übersetzungsdienst davor, und Software, die eine ::1-Verbindung erwartet, fällt auf die Nase. Filtern ist der Weg, nicht Verstecken.
# Falls doch abgeschaltet wurde: Zustand sichtbar machen
sysctl net.ipv6.conf.all.disable_ipv6
Steht dort 1, ist der laufende Betrieb möglicherweise seit Monaten auf einer halben Konfiguration unterwegs, inklusive Firewallregeln, die nie greifen mussten und deshalb nie geprüft wurden.
Geschrieben aus dem laufenden Betrieb: MRMedia betreibt eigene Hosts, Kundendienste und deren Härtung in der EU. Eine veraltete Anleitung ist hier ein Sicherheitsproblem, kein Schönheitsfehler. Korrekturen bitte über Discord.