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:

AdresseBedeutung
127.0.0.1:3306nur vom Server selbst erreichbar
0.0.0.0:8080 oder [::]:8080auf 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

PortDienstMuss öffentlich sein?Maßnahme
22SSHjanur Schlüssel + fail2ban
80 / 443Reverse Proxy (Webseiten)jaZertifikate aktuell halten
81Admin-Oberfläche des Proxysneinschließen, Zugriff per Tunnel
3306Datenbankneinnur 127.0.0.1
8006Weboberfläche der Virtualisierungneinschließen, Zugriff per Tunnel
8080, 8081Testseite, DB-Verwaltungneinschließen oder an 127.0.0.1 binden
9443Container-Verwaltungneinschließ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

  1. Messen (vorher): ss -tulpn und nmap von außen, Ergebnis in einer Datei speichern.
  2. Entscheiden: Pro Port fragen „Muss das aus dem Internet erreichbar sein?“ Meist nein.
  3. 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.
  4. 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.