Welche Ports sind wirklich offen? Angriffsfläche messen und verkleinern
Jeder Port, auf dem ein Dienst aus dem Internet antwortet, ist eine Tür. Bei einem gewachsenen Server weiß man selten, wie viele es sind. Vor dem Absichern steht deshalb die Bestandsaufnahme.
Innen und außen sind zwei verschiedene Sichten
Von innen (auf dem Server): Welcher Prozess lauscht wo?
ss -tulpn
In der Spalte Local Address steht der entscheidende Unterschied:
| Adresse | Bedeutung |
127.0.0.1:3306 | nur vom Server selbst erreichbar |
0.0.0.0:8080 oder [::]:8080 | auf allen Netzwerkschnittstellen, also potenziell aus dem Internet (IPv4 bzw. IPv6) |
Von außen (von einem anderen Rechner, nur bei eigenen Systemen!):
nmap -Pn -p- -T4 203.0.113.10 # alle 65.535 TCP-Ports
nmap -Pn -6 -p- 2001:db8::10 # dasselbe über IPv6
Nur die Messung von außen zeigt, was Firewall, Router und Weiterleitungen tatsächlich durchlassen. Die Innensicht kann täuschen. Vergessen wird oft IPv6: Ist nur IPv4 geschützt, ist ein Dienst über IPv6 womöglich weiter offen.
Beispiel: Inventur eines gewachsenen Servers
| Port | Dienst | Muss öffentlich sein? | Maßnahme |
| 22 | SSH | ja | nur Schlüssel + fail2ban |
| 80 / 443 | Reverse Proxy (Webseiten) | ja | Zertifikate aktuell halten |
| 81 | Admin-Oberfläche des Proxys | nein | schließen, Zugriff per Tunnel |
| 3306 | Datenbank | nein | nur 127.0.0.1 |
| 8006 | Weboberfläche der Virtualisierung | nein | schließen, Zugriff per Tunnel |
| 8080, 8081 | Testseite, DB-Verwaltung | nein | schließen oder an 127.0.0.1 binden |
| 9443 | Container-Verwaltung | nein | schließen, Zugriff per Tunnel |
Ergebnis der Beispielrechnung: Aus 14 offenen Ports werden 3 (22, 80, 443). Die Angriffsfläche schrumpft um rund 80 %, und jeder geschlossene Port ist ein Dienst weniger, der Sicherheitsupdates braucht.
Die Docker-Falle
Wer in compose.yaml schreibt
ports:
- "8080:80"
veröffentlicht den Port auf 0.0.0.0, also für die ganze Welt. Docker trägt seine Regeln direkt in die iptables-Tabellen ein, und zwar so, dass sie vor den Regeln von ufw greifen. Ein ufw deny 8080 hilft deshalb oft nicht. Besser gleich an die lokale Adresse binden:
ports:
- "127.0.0.1:8080:80" # nur lokal; Zugriff über Reverse Proxy oder SSH-Tunnel
Zusätzlich gibt es die Kette DOCKER-USER, in die man eigene Filterregeln legt, die Docker nicht überschreibt.
Vorgehen in vier Schritten
- Messen (vorher):
ss -tulpn und nmap von außen, Ergebnis in einer Datei speichern.
- Entscheiden: Pro Port fragen „Muss das aus dem Internet erreichbar sein?“ Meist nein.
- Schließen – immer in dieser Reihenfolge: zuerst den Zugang für dich selbst sichern (SSH offen, Tunnel getestet, Konsole des Hosters getestet), dann Ports zumachen. Änderungen einzeln und mit Rückweg.
- Erneut messen und die beiden Ergebnisse vergleichen.
Nach dem Neustart noch einmal messen! Firewall-Regeln, die nur mit einem Befehl gesetzt wurden, sind nach einem Reboot weg. Und umgekehrt tauchen alte, vergessene Weiterleitungen aus Konfigurationsdateien wieder auf. Dauerhaft wird eine Regel erst in /etc/nftables.conf, in iptables-persistent oder in der Firewall-Konfiguration der Virtualisierung.
Auch die Firewall selbst braucht ein Sicherheitsnetz
- Zuerst die Regel für den eigenen SSH-Zugang, dann erst „Standard: verwerfen“.
- Wie beim SSH-Umbau: ein Timer, der die Regeln nach zehn Minuten zurücksetzt, falls man sich ausgesperrt hat.
- Bei Servern mit Web-Konsole des Hosters bleibt der Notzugang bestehen, auch wenn alles andere zu ist.
Und wenn ich doch von außen an die Oberfläche muss?
Dann in dieser Reihenfolge der Vorlieben: SSH-Tunnel (Einzelperson), VPN wie WireGuard (mehrere Personen), Freigabe nur für feste IPs (nur bei fester Adresse sinnvoll, bei wechselnder Heim-IP sperrt man sich aus). Ein Port, der „nur kurz“ offen bleibt, bleibt meist für Monate offen.
Man schützt nur, was man kennt. Erst messen, dann schließen, dann nach dem Neustart noch einmal messen.