Zum Inhalt springen
SHIELDMYSERVER

Eingehend dichtmachen: nur was hören muss, hört

Erst prüfen, was tatsächlich lauscht, dann Dienste auf 127.0.0.1 binden, dann eine nftables-Grundregel, in dieser Reihenfolge, weil die Firewall der schwächste der drei Schritte ist.

hochDiese Woche. Deutlich erhöhtes Risiko, wenn es liegen bleibt.

veröffentlicht 07.08.2026 · 2 min

Titelbild: Eingehend dichtmachen: nur was hören muss, hört

Die meisten Firewall-Anleitungen fangen mit Regeln an. Das ist der zweite Schritt. Der erste ist herauszufinden, was überhaupt lauscht und der beste Schutz ist, dass ein Dienst gar nicht erst nach außen hört.

Links Ports, die von außen erreichbar sind, teils berechtigt, teils nicht. In der Mitte der Server. Rechts Dienste, die auf 127.0.0.1 gebunden sind und von außen nicht existieren.
Ein Dienst, der auf 127.0.0.1 hört, braucht keine Firewallregel, er ist von außen nicht da.

Schritt 1: Bestandsaufnahme#

sudo ss -tulpn | grep LISTEN

Die Ausgabe lesen:

Was dort stehtBedeutung
0.0.0.0:443alle IPv4-Adressen, von außen erreichbar
[::]:443alle IPv6-Adressen, meist inklusive IPv4
127.0.0.1:5432nur lokal, von außen nicht vorhanden
[::1]:5432nur lokal über IPv6
10.99.0.5:9100nur über diese eine Schnittstelle

Für jede Zeile mit 0.0.0.0 oder [::] eine Frage: Muss das wirklich von außen erreichbar sein? In den meisten Fällen lautet die Antwort nein, Datenbanken, Metrik-Endpunkte, Verwaltungsoberflächen und Debug-Ports gehören hinter einen Reverse-Proxy oder ein VPN, nicht ins offene Netz.

Schritt 2: Dienste lokal binden#

Das ist wirksamer als jede Firewallregel, weil es keine Regel gibt, die man versehentlich löschen kann.

# PostgreSQL — /etc/postgresql/17/main/postgresql.conf
listen_addresses = 'localhost'
# Docker Compose: Port nur lokal veröffentlichen
services:
  db:
    ports:
      - "127.0.0.1:5432:5432"   # nicht "5432:5432"
# Prometheus node-exporter — nur über das VPN-Netz
[Service]
ExecStart=/usr/local/bin/node_exporter --web.listen-address=10.99.0.5:9100

Nach jeder Änderung erneut ss -tulpn, die Datei sagt, was gemeint war, ss sagt, was passiert ist.

Schritt 3: Die Grundregel#

Erst jetzt die Firewall, als zweite Verteidigungslinie für den Fall, dass ein Dienst doch nach außen bindet.

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;

        ct state established,related accept
        iif "lo" accept
        ct state invalid drop

        # ICMP nicht komplett verwerfen: ohne Fragmentation-Needed bricht die
        # Pfad-MTU-Erkennung, und Verbindungen hängen scheinbar grundlos.
        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, nd-neighbor-solicit, nd-neighbor-advert } accept

        tcp dport 22 ct state new limit rate 10/minute accept comment "SSH"
        tcp dport { 80, 443 } accept comment "Web"

        counter comment "verworfen eingehend"
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
    }
}
sudo nft -c -f /etc/nftables.conf      # nur prüfen
sudo systemctl enable --now nftables
sudo nft list ruleset
Vor dem Laden

policy drop trennt jede Verbindung, deren Port nicht erlaubt ist, auch deine SSH-Sitzung, wenn SSH auf einem anderen Port läuft und hier fehlt. Lege vorher einen Rückfall-Timer an:
sudo sh -c 'sleep 120 && nft flush ruleset' &
Läuft die Verbindung noch, brichst du ihn ab. Läuft sie nicht, räumt er in zwei Minuten auf.

Der Fehler, der am häufigsten übrig bleibt: IPv6#

Klassische iptables-Regeln gelten nur für IPv4. Ist IPv6 konfiguriert und der Dienst hört auf [::], ist er über IPv6 erreichbar, während iptables -L beruhigend aussieht.

Die inet-Tabelle oben deckt beides in einem Regelwerk ab. Prüfen lässt sich das nur von außen:

# Von einer anderen Maschine aus — nur eigene Adressen scannen
nmap -Pn -p- --min-rate 2000 203.0.113.10
nmap -6 -Pn -p- --min-rate 2000 2001:db8::10

Ein Scan von der Maschine auf sich selbst läuft über Loopback und sagt nichts über die Erreichbarkeit von außen.

Prüfen, ob die Regeln greifen#

# Trefferzähler pro Regel: welche greift nie, welche zu oft?
sudo nft -a list ruleset | grep counter

# Was wurde in den letzten 24 Stunden verworfen?
sudo journalctl -k --since "24 hours ago" | grep -i 'nft\|drop' | tail -20

Ein Zähler bei null ist entweder eine überflüssige Regel oder ein Hinweis, dass der Verkehr woanders vorbeiläuft, beides lohnt einen Blick.

Was hier bewusst fehlt#

Die ausgehende Richtung. Sie ist die, an der ein Einbruch auffällt, und deshalb ein eigener Beitrag: Ausgehend begrenzen.

Und wenn Docker im Spiel ist, gilt ein Teil der obigen Aussagen nicht mehr, Docker schreibt eigene Regeln und veröffentlicht Ports an der Firewall vorbei. Dazu Docker umgeht deine Firewall.

MRMedia

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.