InfraFenceInfraFence

Live Security Operations

Loslegen

So stoppst du SSH-Brute-Force-Angriffe

Zuletzt aktualisiert:

Jeder Server, dessen Port 22 aus dem Internet erreichbar ist, bekommt wenige Minuten nach dem Start die ersten Passwortversuche, den ganzen Tag, von Tausenden Adressen. Meist sind es Bots, die root, admin und gängige Namen mit Listen geleakter Passwörter durchprobieren. Hinein kommen sie nur, wo ein Passwort schwach ist, aber sie füllen die Logs, kosten CPU, und ein einziges schwaches Konto genügt.

Die Lösung besteht aus mehreren Schichten: Passwörter nutzlos machen (nur noch Schlüssel), root aus dem Spiel nehmen, dann den Rest sperren und begrenzen. Die Befehle unten gelten für Debian und Ubuntu sowie für die RHEL-Familie (RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora).

Prüfen, ob du angegriffen wirst

Der SSH-Daemon protokolliert jeden fehlgeschlagenen Versuch. Zähle die letzten 24 Stunden und sieh dir dann an, welche Adressen die meisten schicken:

Jede Distribution mit systemd
sudo journalctl --since "24 hours ago" | grep -cE "Failed password|Invalid user"
Jede Distribution mit systemd
sudo journalctl --since "24 hours ago" \
  | grep -E "Failed password|Invalid user" \
  | grep -oE "from [0-9a-fA-F.:]+ port" | awk '{print $2}' \
  | sort | uniq -c | sort -rn | head -20

Hunderte oder Tausende Zeilen am Tag sind für einen Server mit öffentlicher IP normal. Wird das Journal nicht über Neustarts hinweg aufbewahrt, stehen dieselben Zeilen unter Debian und Ubuntu in /var/log/auth.log und in der RHEL-Familie in /var/log/secure.

SSH-Schlüssel einrichten und zuerst testen

Alles Weitere schaltet Passwörter ab, deshalb brauchst du zuerst einen funktionierenden Schlüssel. Erzeuge auf deinem eigenen Rechner einen Schlüssel, kopiere ihn auf den Server und melde dich damit an. Ersetze deploy durch deinen Benutzer und SERVER_IP durch die Adresse des Servers.

Auf deinem Rechner
ssh-keygen -t ed25519 -C "laptop"
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@SERVER_IP
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP

Der letzte Befehl muss dich anmelden, ohne nach dem Passwort des Kontos zu fragen (er darf nach der Passphrase des Schlüssels fragen, die auf deinem Rechner bleibt).

Achtung: Ab hier hältst du eine SSH-Sitzung zum Server offen und machst jeden Test aus einem zweiten Terminal. Sperrt dich eine Änderung aus, kannst du sie über die offene Sitzung rückgängig machen. Finde außerdem vorher die Webkonsole deines Providers (VNC oder seriell); sie funktioniert auch ohne SSH.

Einen sudo-Benutzer anlegen, bevor du root abschaltest

Wenn du dich heute als root anmeldest, lege zuerst einen normalen Benutzer mit sudo-Rechten an und gib ihm dieselben Schlüssel.

Debian / Ubuntu
sudo adduser deploy
sudo usermod -aG sudo deploy
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo useradd -m deploy
sudo passwd deploy
sudo usermod -aG wheel deploy
Die Schlüssel von root zum neuen Benutzer kopieren
sudo mkdir -p /home/deploy/.ssh
sudo cp /root/.ssh/authorized_keys /home/deploy/.ssh/
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
Nur RHEL-Familie, für die SELinux-Labels
sudo restorecon -R /home/deploy/.ssh

Melde dich aus dem zweiten Terminal als neuer Benutzer an und führe sudo -v aus: Es muss das Passwort des Benutzers annehmen. Erst dann geht es weiter.

Passwort-Login und root-Login abschalten

Aktuelle Versionen von Debian, Ubuntu, der RHEL-9-Familie und Fedora lesen zusätzliche Dateien aus /etc/ssh/sshd_config.d/. Prüfe, ob deine das tut:

Jede Distribution
grep -i '^Include' /etc/ssh/sshd_config

Gibt der Befehl Include /etc/ssh/sshd_config.d/*.conf aus, schreibst du die Einstellungen in eine eigene Datei. SSH übernimmt für jede Einstellung den ersten Wert, den es liest, und die Dateien werden in alphabetischer Reihenfolge gelesen. Das Präfix 00- gewinnt also gegen Dateien wie 50-cloud-init.conf, die auf manchen Cloud-Images Passwörter wieder einschalten.

Jede Distribution
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
MaxAuthTries 4
LoginGraceTime 30
EOF

Fehlt die Include-Zeile (RHEL 8 und seine Rebuilds), setzt du dieselben sechs Zeilen direkt in /etc/ssh/sshd_config und ersetzt dort die vorhandenen. Teste dann die Konfiguration und sieh dir die Werte an, die SSH tatsächlich verwendet:

Jede Distribution
sudo sshd -t && echo "config OK"
sudo sshd -T | grep -Ei '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|maxauthtries) '

Jede Zeile muss den Wert zeigen, den du gesetzt hast. Muss sich root weiterhin mit einem Schlüssel anmelden, etwa für einen Backup-Job, nimm PermitRootLogin prohibit-password statt no. Lade SSH neu: Offene Sitzungen bleiben verbunden.

Debian / Ubuntu
sudo systemctl reload ssh
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo systemctl reload sshd

Achtung: Schließ die offene Sitzung noch nicht. Melde dich aus dem zweiten Terminal mit deinem Schlüssel an und prüfe dann, dass ein Passwort abgelehnt wird: Der Befehl unten muss mit Permission denied (publickey) enden.

Auf deinem Rechner
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password deploy@SERVER_IP

Den SSH-Port ändern und wissen, was das nicht bringt

Ein anderer SSH-Port als 22 verringert das Rauschen in den Logs, weil die meisten Bots nur 22 probieren. Sicherer wird SSH dadurch nicht: Portscanner finden einen neuen Port innerhalb von Stunden, ein gezielter Angreifer sofort. Mit reinem Schlüssel-Login spielt der Port kaum eine Rolle. Mach es für sauberere Logs, nicht für die Sicherheit, und erst nach den Schritten oben.

Wähle einen Port (hier 2222), öffne ihn in der Firewall und teile in der RHEL-Familie SELinux mit, dass SSH ihn nutzen darf:

Debian / Ubuntu mit ufw
sudo ufw allow 2222/tcp
RHEL-Familie mit firewalld und SELinux
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222

Öffne den Port auch in der Cloud-Firewall oder Security Group deines Providers. Setze dann den Port und starte SSH neu:

Jede Distribution
echo "Port 2222" | sudo tee /etc/ssh/sshd_config.d/01-port.conf
sudo sshd -t && echo "config OK"

Ab Ubuntu 24.04 kann SSH über ssh.socket gestartet werden: Gibt der erste Befehl unten active aus, führe alle vier Zeilen aus, sonst nur die letzte.

Debian / Ubuntu
systemctl is-active ssh.socket
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo systemctl restart ssh
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo systemctl restart sshd
Auf deinem Rechner
ssh -p 2222 deploy@SERVER_IP

Achtung: Entferne die Regel für Port 22 erst dann aus der Firewall, wenn der Login über den neuen Port funktioniert. Auch fail2ban, sshguard und die Verbindungslimits unten müssen den neuen Port verwenden.

Hartnäckige Angreifer mit fail2ban oder sshguard sperren

Ohne Passwörter können die Rateversuche nicht mehr gelingen, aber wenn du die Adressen sperrst, die es immer weiter versuchen, sinken Last und Rauschen. fail2ban liest das Log und sperrt eine Adresse nach einer bestimmten Zahl von Fehlversuchen an der Firewall.

Debian / Ubuntu
sudo apt update
sudo apt install -y fail2ban python3-systemd
Rocky Linux, AlmaLinux, CentOS Stream (EPEL)
sudo dnf install -y epel-release
sudo dnf install -y fail2ban

Unter RHEL selbst und Oracle Linux aktivierst du EPEL so, wie es deren Dokumentation beschreibt, und installierst dann fail2ban. Unter Fedora liegt es in den Hauptrepositorys. Amazon Linux 2023 kann EPEL nicht nutzen: Nimm dort stattdessen das Firewall-Limit unten.

Einstellungen gehören in jail.local, nie in jail.conf, das bei Updates überschrieben wird. Prüfe, ob du schon eine hast, und lege sie dann an. Ersetze YOUR_OFFICE_IP durch die festen Adressen, von denen aus du arbeitest, oder lösch den Eintrag, und setze port auf deinen SSH-Port, falls du ihn geändert hast.

Jede Distribution
ls -l /etc/fail2ban/jail.local
Jede Distribution
sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_OFFICE_IP
bantime = 1h
bantime.increment = true
findtime = 10m
maxretry = 5

[sshd]
enabled = true
backend = systemd
port = ssh
EOF

Damit wird eine Adresse nach 5 Fehlversuchen in 10 Minuten für eine Stunde gesperrt, und bei jeder Wiederkehr länger. backend = systemd liest das Journal und funktioniert damit auch unter Debian 12 und neuer, wo es /var/log/auth.log eventuell nicht gibt.

Jede Distribution
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Bei einem Angriff steigen Total failed und Currently banned innerhalb weniger Minuten. Bleibt Total failed bei 0, während das Journal fehlgeschlagene Logins zeigt, liest das Jail nicht das richtige Log. So hebst du eine Sperre auf:

Jede Distribution
sudo fail2ban-client set sshd unbanip 203.0.113.7

sshguard, die schlankere Alternative

sshguard erledigt dieselbe Aufgabe mit weniger Konfiguration und ist für Debian und Ubuntu paketiert (und in EPEL). Trag zuerst deine eigenen Adressen in die Whitelist ein und beobachte dann bei einem Angriff mit sudo journalctl -u sshguard -f die Sperren. Nutze eines der beiden, nicht beide.

Debian / Ubuntu
sudo apt install -y sshguard
echo "YOUR_OFFICE_IP" | sudo tee -a /etc/sshguard/whitelist
sudo systemctl restart sshguard

SSH an der Firewall begrenzen oder einschränken

Unter Ubuntu und Debian mit ufw weist limit eine Adresse ab, die 6 oder mehr Verbindungen in 30 Sekunden öffnet. Es ersetzt eine einfache allow 22/tcp-Regel. Zeigt sudo ufw status zusätzlich eine OpenSSH-Regel, lösch sie, sobald das Limit aktiv ist (sudo ufw delete allow OpenSSH), denn sie würde vor dem Limit greifen.

Debian / Ubuntu mit ufw
sudo ufw limit 22/tcp
sudo ufw enable
sudo ufw status verbose

Achtung: Ist ufw noch nicht aktiv, blockiert ufw enable sofort jeden Port ohne Regel. Erlaube vorher die Dienste, die der Server anbietet (zum Beispiel sudo ufw allow 80,443/tcp), und lass die offene Sitzung stehen.

Die Rich Rules von firewalld kennen ein limit, aber es zählt alle Quellen zusammen: Ein Angriff kann das Kontingent aufbrauchen und dich mit aussperren. Für Limits pro Adresse nimmst du in der RHEL-Familie fail2ban.

SSH nur von deinen Adressen erlauben

Der wirksamste Schritt, wenn du von festen Adressen oder über ein VPN arbeitest: Niemand sonst erreicht SSH überhaupt.

Debian / Ubuntu mit ufw
sudo ufw allow from YOUR_OFFICE_IP to any port 22 proto tcp
sudo ufw delete limit 22/tcp
sudo ufw status numbered
RHEL-Familie mit firewalld
sudo firewall-cmd --permanent --zone=trusted --add-source=YOUR_OFFICE_IP
sudo firewall-cmd --reload
sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --reload

Achtung: Das sperrt jede andere Adresse aus, auch deine, wenn sie sich ändert. Teste nach dem ersten Reload einen neuen Login, bevor du die öffentliche SSH-Regel entfernst, und halte die Webkonsole des Providers als Rückweg bereit.

Wie InfraFence mit SSH-Brute-Force umgeht

Der InfraFence-Agent liest das SSH-Log, während es geschrieben wird, und sperrt eine Adresse an der Firewall, sobald sie innerhalb des Zeitfensters die Fehlerschwelle erreicht. Beides kannst du im Dashboard ändern.

  • 15 Erkennungsmuster: falsche Passwörter, ungültige Benutzer, PAM-Fehler, Scans vor der Authentifizierung, Protokollfehler und Abbrüche beim Schlüsselaustausch.
  • Steigende Sperren: 24 Stunden, 7 Tage, 30 Tage, dann dauerhaft, oder eine Dauer deiner Wahl. Optional wird eine auf einem Server gesperrte Adresse auf allen deinen Servern gesperrt.
  • Derselbe Schutz für Logins bei Postfix, Dovecot, MySQL, PostgreSQL, MongoDB, Pure-FTPd, ProFTPD und vsftpd.
  • Die Härtungsprüfungen melden root-Login, Passwort-Login, den Standardport und ein hohes MaxAuthTries. MaxAuthTries wird mit einem Klick korrigiert, in einer eigenen Datei (/etc/ssh/sshd_config.d/00-infrafence-hardening.conf), die getestet wird, bevor SSH neu geladen wird. root-Login, Passwörter und der Port können dich aussperren, deshalb werden sie stattdessen Schritt für Schritt erklärt, wie in dieser Anleitung.
  • Jede SSH-Sitzung wird von der Anmeldung bis zur Abmeldung verfolgt und bekommt einen Risikowert, damit du weißt, wer angemeldet war, als etwas anderes angeschlagen hat.

Es arbeitet neben fail2ban: Der Agent erkennt es und hält seine eigenen Regeln in separaten INFRAFENCE-Chains, die er nach einem Firewall-Reload wiederherstellt.

Fragen

Reicht es, den SSH-Port zu ändern, um Brute Force zu stoppen?
Nein. Es senkt die Zahl der Versuche in den Logs, weil die meisten Bots nur Port 22 probieren, aber Scanner finden den neuen Port schnell. Erst der reine Schlüssel-Login macht die Rateversuche nutzlos.
Soll ich fail2ban oder sshguard nehmen?
Für SSH funktionieren beide. fail2ban hat mehr Filter für andere Dienste und mehr Optionen, sshguard braucht weniger Konfiguration. Nutze eines, nicht beide, damit sie sich nicht um dieselben Adressen streiten.
Ich habe Passwörter abgeschaltet und sehe trotzdem fehlgeschlagene Logins. Stimmt etwas nicht?
Nein, alles in Ordnung. Bots versuchen es weiter, weil sie nicht wissen, dass Passwörter abgeschaltet sind. Die Versuche scheitern, bevor überhaupt ein Passwort geprüft wird. Sperren und Verbindungslimits verringern das Rauschen.

Kostenlos auf 1 Server testen

Starter ist für einen Server kostenlos, mit vollem Schutz und automatischen Sperren. Ohne Kreditkarte.

Installiere den Agenten als root, mit deinem Token anstelle von <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

Das Token erstellst du im Dashboard unter Server › Server hinzufügen.