Sobald Login per SSH-Key funktioniert und ein eigener Benutzer mit sudo-Rechten existiert, kommt der Härtungs-Schritt. Ziel: einen frischen Server so konfigurieren, dass automatisierte Brute-Force-Versuche keinerlei Angriffsfläche finden — Passwort-Login komplett aus, Zugriff auf bestimmte Benutzer beschränkt, MaxAuthTries und LoginGraceTime straff gesetzt, fail2ban als Fallback. Plus: ehrliche Einschätzung, ob der Port-Wechsel wirklich etwas bringt.
Warum SSH härten — auch mit Key-Login?
Wenn der Login bereits per Key läuft, sind klassische Passwort-Brute-Force-Angriffe ohnehin chancenlos. Trotzdem sind weitere Schritte sinnvoll:
- Defense in Depth. Sicherheit basiert nicht auf einer einzigen Schicht. Falls ein privater Schlüssel kompromittiert wird oder eine OpenSSH-Schwachstelle auftritt, helfen die zusätzlichen Schichten, das Zeitfenster zu verkürzen.
- Log-Hygiene. Ein offener SSH-Port wird ständig durchprobiert. Selbst wenn die Versuche scheitern, fluten sie die Logs und machen echte Anomalien schwer auffindbar. Hardening reduziert die Log-Last drastisch.
- Compliance & Audit. Wenn der Server für Kunden- oder Geschäftsdaten genutzt wird, wird oft ein nachweislich abgesicherter SSH-Zugang verlangt — egal, ob praktisch nötig oder nicht.
Die Schritte hier sind drop-in-konform: alle Änderungen landen in /etc/ssh/sshd_config.d/, nicht in der Hauptdatei. Das vermeidet Konflikte mit Distro-Updates.
Passwort-Login komplett deaktivieren
Die kritischste Maßnahme. Solange der Server Passwörter akzeptiert, läuft im Hintergrund permanent ein Brute-Force-Wettlauf — auch wenn dein Account längst Key-only nutzt, bleiben System-Accounts wie admin, ubuntu, git ein attraktives Ziel.
sudo nano /etc/ssh/sshd_config.d/10-hardening.conf# Authentifizierung
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
PermitEmptyPasswords noErklärung der einzelnen Zeilen:
- PasswordAuthentication no — kein Passwort-Login, ausschließlich Key.
- KbdInteractiveAuthentication no — schließt eine zweite Tür, durch die manche Distros sonst doch wieder Passwörter durchlassen (PAM-basiert).
- ChallengeResponseAuthentication no — Legacy-Variante derselben Tür, sicherheitshalber explizit aus.
- UsePAM yes — bleibt an, weil PAM für Account-Lockout, lastlog usw. zuständig ist. Sicherheitsrisiko ist es nur in Verbindung mit aktivem
KbdInteractiveAuthentication. - PermitEmptyPasswords no — sollte nie auf
yesstehen. Doppelt absichern schadet nicht.
Login-Versuche und Zeitfenster begrenzen
Ein Angreifer mit einem gestohlenen Key-Auswahl-Set kann pro Verbindung mehrere Keys ausprobieren. Außerdem hält ein nicht-authentifizierender Verbindungsversuch eine Slot offen — knappe Zeit-/Versuchs-Limits sind eine billige zweite Schicht.
# Versuche & Zeitfenster
MaxAuthTries 3
MaxSessions 4
LoginGraceTime 30- MaxAuthTries 3 — pro Verbindung maximal 3 Authentifizierungs-Versuche (Default 6). Bei 3 Versuchen wird die Verbindung getrennt.
- MaxSessions 4 — maximal 4 parallele Multiplex-Sessions pro Verbindung. Default 10 ist großzügig; 4 reicht für die meisten realen Szenarien.
- LoginGraceTime 30 — der Server schließt nicht authentifizierte Verbindungen nach 30 Sekunden. Default 120 ist zu großzügig — Brute-Force-Tools profitieren von langen Grace-Zeiten.
Zugriffsliste — wer darf überhaupt einloggen
Standardmäßig darf sich jeder Linux-Benutzer per SSH einloggen, sofern er einen Key hat. Auf einem produktiven Server ist das selten gewünscht — Service-Accounts (www-data, postgres, redis) sollen sich definitiv nicht interaktiv einloggen können.
Zwei Mechanismen, einer reicht meistens:
# Variante A — Whitelist über User-Namen
AllowUsers max alice
# Variante B — Whitelist über Gruppe (saubere Variante)
# AllowGroups ssh-usersAllowUsers ist der direkte Weg — perfekt, wenn nur eine Handvoll Personen Zugriff haben. AllowGroups skaliert besser: einmal eine Gruppe ssh-users anlegen, jeden berechtigten Account in die Gruppe aufnehmen, fertig.
Gruppe anlegen (nur falls Variante B):
sudo groupadd ssh-users
sudo usermod -aG ssh-users maxWichtig: Sobald
AllowUsersoderAllowGroupsgesetzt sind, darf nur noch wer hier gelistet ist einloggen. Vergiss nicht, deinen eigenen Account hinzuzufügen — sonst sperrst du dich aus.
Port-Wechsel — bringt das was?
Der Port-Wechsel (Standard 22 auf etwas wie 22022 oder 2222) ist ein dauernd diskutiertes Thema. Ehrliche Einordnung:
Was ein Port-Wechsel tatsächlich bringt:
- Drastisch weniger Logs. Das Internet-Untergrund-Skript-Repertoire pingt fast ausschließlich Port 22. Auf einem anderen Port verschwindet 90 % des Hintergrundrauschens.
- Niedrigere CPU-Last. Jeder Verbindungsversuch kostet Krypto-Operationen. Auf einem kleinen VPS macht das einen messbaren Unterschied.
Was es nicht bringt:
- Keine echte Sicherheit. Ein zielgerichteter Angreifer scannt alle 65535 Ports in unter einer Minute mit
nmapodermasscan. Security-through-Obscurity allein hält niemanden auf.
Empfehlung: Wenn du den Port wechselst, dann nicht auf 2222 (gängigster Alternativ-Port — wird auch gescannt), sondern auf eine zufällige Zahl im 1024–49151-Range:
Port 47823Firewall öffnen (Beispiel ufw):
sudo ufw allow 47823/tcp
# erst neuen Port testen, dann alten Port (22) schließen:
sudo ufw delete allow 22/tcpIm Provider-Panel ggf. Cloud-Firewall ebenfalls anpassen. Und: ~/.ssh/config lokal aktualisieren, damit der Alias den neuen Port kennt.
fail2ban als Fallback
fail2ban liest SSH-Logs, erkennt wiederholte Fehlversuche und sperrt die Quell-IP per iptables/nftables. Auch wenn Passwort-Login aus ist, sperrt es Scanner aus, die mit ungültigen Keys/Usernames spammen.
Installation:
sudo apt install fail2ban -ysudo dnf install epel-release -y
sudo dnf install fail2ban -yDie Standard-Konfiguration /etc/fail2ban/jail.conf niemals direkt editieren — sie wird durch Updates überschrieben. Eigene Konfiguration kommt in /etc/fail2ban/jail.local:
[DEFAULT]
# IPs, die nie gesperrt werden (eigene IP eintragen!)
ignoreip = 127.0.0.1/8 ::1
# Bantime, Findtime, Maxretry
bantime = 1h
findtime = 10m
maxretry = 5
# Backend: systemd-journal statt /var/log
backend = systemd
[sshd]
enabled = true
# bei nicht-Standard-Port: hier nachziehen
port = sshErklärung:
- bantime 1h — gesperrte IP bleibt 1 Stunde gesperrt.
- findtime 10m + maxretry 5 — 5 Fehlversuche in 10 Minuten triggern den Bann.
- backend systemd — moderne Distros loggen über journald, nicht in
/var/log/auth.log.
Service starten und Status prüfen:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshdKonfiguration testen und übernehmen
Vor jedem Reload die Konfiguration validieren — ein Tippfehler in einer Hardening-Datei kann den SSH-Service crashen, was bei laufender Verbindung noch keine Aussperrung bedeutet, beim nächsten Restart aber sehr wohl.
sudo sshd -tKein Output = alles gut. Bei Fehlern wird die fehlerhafte Direktive samt Datei und Zeilennummer gemeldet.
Effektive Konfiguration prüfen — alle Defaults plus Drop-Ins zusammengefasst:
sudo sshd -T | grep -iE 'password|maxauth|allowusers|port|logingrace'Wenn alles passt, reload (kein restart) — bestehende Sessions laufen weiter:
sudo systemctl reload ssh # Debian/Ubuntu
sudo systemctl reload sshd # RHEL-FamilieVerifikation aus einer zweiten Session — vor dem Schließen der ersten:
ssh max@203.0.113.42
# erfolgreicher Key-Login; falls Port geändert: -p <neuer port>Sicherheits-Checkliste
PasswordAuthentication noundKbdInteractiveAuthentication nogesetzt, mitsshd -TverifiziertMaxAuthTries 3,LoginGraceTime 30,MaxSessions 4aktivAllowUsersoderAllowGroupsgesetzt, eigener Account dort gelistet- Service-Accounts (
www-data,postgres…) nicht in der Whitelist - Falls Port-Wechsel: Provider-Firewall und Host-Firewall (ufw/firewalld) angepasst, alter Port geschlossen
fail2banläuft,fail2ban-client status sshdzeigt aktiven Jailsshd -tbestanden,reloadstattrestartbenutzt- Zweite Test-Session vor Verbindungs-Trennung erfolgreich
Häufige Fehler beim SSH-Hardening
Hauptdatei sshd_config editiert
Distros laden via Include /etc/ssh/sshd_config.d/*.conf. Eigene Direktiven gehören in eine Drop-in-Datei dort — im Hauptfile werden sie früher oder später durch Distro-Updates überschrieben oder geraten in Konflikt mit dem Default-Set.
AllowUsers ohne eigenen Account
Klassischer Self-Lock. Vor dem Reload zwingend prüfen, dass der eigene Username (oder die eigene Gruppe) in der Whitelist steht. Eine zweite SSH-Session offen lassen, falls der Reload schiefgeht.
fail2ban mit zu strengem Limit und vergessener Eigen-IP
Wenn bantime/maxretry knapp gesetzt sind und die eigene Heim-IP nicht in ignoreip steht, kann ein versehentlich kaputter Login zum Self-Bann führen. Eigene IP unbedingt freischalten — oder per VPN/Provider-Konsole einen Backup-Pfad sicherstellen.
Port-Wechsel ohne Firewall-Anpassung
Server lauscht auf dem neuen Port, ufw oder die Provider-Firewall lassen aber nur 22 durch — Login schlägt fehl, ohne dass es nach einem SSH-Problem aussieht. Beide Firewall-Schichten anpassen, alten Port erst nach erfolgreichem Test schließen.
PermitRootLogin yes vergessen abzuschalten
Wenn der Schritt aus dem User-/sudo-Artikel übersprungen wurde, ist der root-Zugang trotz Hardening weiter offen. Hier mit nachziehen: PermitRootLogin no in der Drop-in-Datei.
backend = auto in fail2ban auf systemd-Distros
Auf Distros, die nicht mehr in /var/log/auth.log schreiben (Ubuntu 22.04+ ohne rsyslog), findet auto keine Log-Quelle und fail2ban schweigt. backend = systemd ist heute der korrekte Default für moderne Systeme.
Verwandte Artikel
- Eigenen Benutzer anlegen und sudo einrichten — der Schritt davor (root-Lock kommt von dort)
- Erste SSH-Verbindung und SSH-Key einrichten — Grundlage für Key-only-Login
- Linux für den eigenen Server wählen — Distro bestimmt Service-Name (
sshvs.sshd) - Linux-Doku: SSH-Konfiguration — Tiefen-Doku zu sshd_config-Optionen
Externe Quellen
- OpenSSH sshd_config(5) Manpage — vollständige Direktiven-Referenz
- Mozilla OpenSSH Guidelines — empfohlene Konfiguration für Modern- und Intermediate-Profile
- fail2ban Wiki — Jails, Filter, Actions
- CIS-Benchmarks — formale Hardening-Vorgaben pro Distribution
- ssh-audit — Tool, das den eigenen Server gegen Best Practices testet (Algorithmen-Set, Schwachstellen)