SSH-Hardening Deep-Dive: sshd_config, Match-Blöcke und ssh-audit für KMU-Server
Kommentierte sshd_config als Drop-in für KMU-Server: Post-Quantum-Key-Exchange, Timeouts nach CIS, Match-Blöcke für SFTP-only-User und Admin-Netze, Prüfung mit ssh-audit, Schritt für Schritt ohne Aussperr-Risiko.
Geprüft am 30.09.2026 · für OpenSSH 9.9
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Die OpenSSH-Standardwerte bieten noch schwache Diffie-Hellman-Gruppen an. Diese Anleitung härtet sshd auf Ubuntu 22.04/24.04, Debian 12 oder RHEL 9/10 per Drop-in, richtet Match-Blöcke für SFTP-only-User und Admin-Netze ein und prüft das Ergebnis mit ssh-audit, ohne dass Sie sich aussperren. Schlüssel-Anmeldung: SSH-Key-Authentifizierung einrichten; Firewall und Fail2ban: Linux-Server absichern mit UFW und Fail2ban.
Voraussetzungen
- Server mit Ubuntu 22.04/24.04 LTS, Debian 12 oder RHEL 9/10 – OpenSSH >= 8.5 für sntrup761x25519, >= 9.9 für mlkem768x25519
- Root- oder sudo-Zugriff auf dem Zielserver
- Eine aktive, offene SSH-Sitzung während der gesamten Konfigurationsarbeit (Sicherheitsnetz gegen Aussperren)
- Konsolen-Zugang (KVM, IPMI oder Cloud-Konsole) als Notfall-Fallback
- Funktionierende Ed25519-Schlüssel für alle Admin-Benutzer (siehe SSH-Key-Authentifizierung), denn danach ist die Passwort-Anmeldung deaktiviert
- Backup der aktuellen Konfiguration:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - ssh-audit als Paket (Debian/Ubuntu), per
pipxoder Snap - Für SFTP-Nutzer: geplante Benutzerkonten, Gruppen und Verzeichnisstruktur
Schritt 1: ssh-audit installieren und Ist-Zustand erfassen
Erfassen Sie zuerst den Ist-Zustand. ssh-audit wertet nur den SSH-Handshake aus, ohne sich anzumelden, und bewertet jeden angebotenen Algorithmus.
# Installation auf Debian/Ubuntu:
sudo apt install ssh-audit
# Alternativ aktuelle Version per pipx (pip3 scheitert auf Debian 12/Ubuntu 24.04 an PEP 668):
pipx install ssh-audit
# Ist-Zustand des eigenen Servers erfassen:
ssh-audit localhost
# Nur Fehler und Grade anzeigen (schneller Überblick):
ssh-audit localhost 2>&1 | grep -E '\[fail\]|\[warn\]'
# Eingebaute Härtungsanleitungen auflisten:
ssh-audit --list-hardening-guides
# Härtungsanleitung für Ubuntu 24.04 abrufen (Namen aus der Liste übernehmen):
ssh-audit --get-hardening-guide "Ubuntu 24.04 Server"
Jede Zeile trägt eine Bewertung: [fail] = entfernen, [warn] = schwach, [info] = Hinweis; Eine Note (Grade) vergibt nur der Online-Dienst auf ssh-audit.com, nicht das Kommandozeilenwerkzeug. Auf einem frisch installierten Server erscheinen meist mehrere [fail]- und [warn]-Zeilen.
Verifizieren: ssh-audit localhost läuft durch und zeigt die OpenSSH-Version unter (gen) software. Speichern Sie die Ausgabe als Ist-Zustand: ssh-audit localhost > ~/ssh-audit-vorher.txt.
Schritt 2: Moduli-Datei filtern
Die Datei /etc/ssh/moduli enthält vordefinierte DH-Gruppen. Entfernen Sie Gruppen unter 4096 Bit, bevor Sie diffie-hellman-group-exchange-sha256 anbieten. Die Spalte 5 enthält die Bitlänge minus 1 (4095 = 4096 Bit).
# Nur Einträge ab 4096 Bit behalten (als root):
sudo cp /etc/ssh/moduli /etc/ssh/moduli.bak
awk '$5 >= 4095' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.safe > /dev/null
sudo mv /etc/ssh/moduli.safe /etc/ssh/moduli
# Anzahl verbleibender Einträge prüfen (sollte mehrere hundert sein!):
wc -l /etc/ssh/moduli
Wichtig: Wenn nach dem Filter zu wenige Einträge übrig bleiben (unter ~50 Zeilen), schlägt diffie-hellman-group-exchange-sha256 zur Laufzeit fehl. Stellen Sie dann /etc/ssh/moduli.bak zurück und prüfen Sie den Filter.
Verifizieren: awk '$5 < 4095' /etc/ssh/moduli | wc -l liefert 0, wc -l /etc/ssh/moduli einen dreistelligen Wert.
Schritt 3: Host-Keys prüfen und ggf. neu generieren
Erzeugen Sie nur fehlende Hostkeys; ein neuer Schlüssel löst bei allen Clients eine Fingerabdruck-Warnung aus.
# Vorhandene Host-Keys auflisten:
ls -la /etc/ssh/ssh_host_*
# Falls kein Ed25519-Key vorhanden:
sudo ssh-keygen -t ed25519 -q -N "" -f /etc/ssh/ssh_host_ed25519_key
# RSA 4096 Bit als Fallback für ältere Clients:
sudo ssh-keygen -t rsa -b 4096 -q -N "" -f /etc/ssh/ssh_host_rsa_key
Verifizieren: sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub zeigt einen Fingerabdruck mit „(ED25519)“, für RSA „4096“ oder mehr Bit.
Schritt 4: Drop-in-Härtungskonfiguration anlegen
Prüfen Sie, ob die Hauptdatei die Drop-ins einbindet (bei aktuellen Ubuntu-, Debian- und RHEL-9-Paketen Standard):
grep 'Include' /etc/ssh/sshd_config
# Erwartete Ausgabe: Include /etc/ssh/sshd_config.d/*.conf
# Falls die Zeile fehlt, ganz oben einfügen:
# sudo sed -i '1s/^/Include \/etc\/ssh\/sshd_config.d\/*.conf\n/' /etc/ssh/sshd_config
Legen Sie nun die Härtungsdatei an. Die Nummer „10“ lädt sie vor späteren Dateien; bei mehreren Drop-ins gilt die erste Definition einer Direktive.
# Datei: /etc/ssh/sshd_config.d/10-hardening.conf
# SSH Hardening Drop-in – s-edv.com 2025/2026
# Kompatibel mit OpenSSH 8.x+ (Ubuntu 22.04+, Debian 12+, RHEL 9+)
# --- Post-quantum + klassische Key Exchange Algorithmen ---
# mlkem768x25519 = Standard ab OpenSSH 10.0 (ML-KEM + X25519, hybrid post-quantum)
# -> erst ab OpenSSH 9.9; auf Ubuntu 22.04/24.04, Debian 12 und RHEL 9 weglassen!
# sntrup761x25519 = Hybrid post-quantum (NTRU Prime + X25519), seit OpenSSH 8.5, Standard seit 9.0
# curve25519 = schnellster klassischer Algorithmus
# dh-group16/18 = RSA-DH 4096/8192 Bit mit SHA-512 als sicherer Fallback
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group16-sha512,diffie-hellman-group-exchange-sha256
# --- Verschlüsselung: nur AEAD-Ciphers + ChaCha20 ---
# Reihenfolge: ChaCha20 (software-optimiert) > AES-GCM 256 > AES-GCM 128 > AES-CTR
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# --- MACs: ausschließlich ETM (Encrypt-then-MAC) ---
# ETM-Varianten sind immun gegen Padding-Oracle-Angriffe
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
# --- Hostkey-Algorithmen: Ed25519 + RSA/SHA-2 only ---
# Kein ssh-rsa (SHA-1, ab OpenSSH 8.8 standardmäßig deaktiviert), kein ecdsa
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com
# --- Aktive Host-Keys ---
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
# --- Authentifizierung ---
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
# --- Timeouts und Limits (CIS-Benchmark-orientiert) ---
LoginGraceTime 30
MaxAuthTries 3
MaxSessions 4
ClientAliveInterval 300
ClientAliveCountMax 2
# --- Sicherheitsverschärfte Defaults ---
PermitEmptyPasswords no
X11Forwarding no
AllowTcpForwarding no
PermitUserEnvironment no
AllowAgentForwarding no
UseDNS no
VersionAddendum none
LogLevel VERBOSE
PrintLastLog yes
Banner /etc/issue.net
# --- SFTP-Subsystem ---
# Nicht hier setzen: Die Hauptdatei definiert "Subsystem sftp" bereits; OpenSSH vor 9.5
# (Ubuntu 22.04, Debian 12) bricht bei doppelter Definition ab. Die SFTP-only-User
# erhalten internal-sftp per ForceCommand in Schritt 5.
Legen Sie die Datei mit sudo tee an und prüfen Sie die Syntax:
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null << 'EOF'
# (Inhalt wie oben einfügen)
EOF
# Syntaxprüfung – MUSS fehlerfrei sein:
sudo sshd -t
# Effektive Konfiguration nach Merge aller Drop-ins anzeigen:
sudo sshd -T | grep -E 'kexalgorithms|ciphers|macs|hostkeyalgorithms|maxauthtries'
Verifizieren: sudo sshd -t gibt nichts aus; sshd -T zeigt exakt die Algorithmen aus der Datei. Meldet es „Bad SSH2 KexAlgorithms“, unterstützt Ihre OpenSSH-Version einen Eintrag nicht (siehe Tabelle unten).
Schritt 5: Match-Blöcke für Admin-Netze und SFTP-only-User
Match-Blöcke gehören hinter alle globalen Direktiven, daher die eigene Datei mit Nummer 90.
# Datei: /etc/ssh/sshd_config.d/90-match-blocks.conf
# === Match-Block: Admin-Netz (Management-VLAN 192.168.10.0/24) ===
# Admins dürfen TCP-Forwarding und Agent-Forwarding nutzen
Match Address 192.168.10.0/24
AllowTcpForwarding yes
AllowAgentForwarding yes
X11Forwarding no
MaxAuthTries 5
# Optional: root-Login nur aus Admin-Netz erlauben
# PermitRootLogin prohibit-password
# === Match-Block: SFTP-only-Gruppe ===
# Alle Mitglieder der Gruppe 'sftponly' werden in ihr Verzeichnis gechrootet
# WICHTIG: ChrootDirectory muss root:root und chmod 755 sein!
# AuthenticationMethods any hebt das globale "publickey" auf, sonst greift das Passwort nicht
Match Group sftponly
ForceCommand internal-sftp -l INFO
ChrootDirectory /srv/sftp/%u
AllowTcpForwarding no
AllowAgentForwarding no
X11Forwarding no
PasswordAuthentication yes
AuthenticationMethods any
# === Match-Block: einzelner Backup-User ===
Match User backupuser
ForceCommand internal-sftp
ChrootDirectory /backup/sftp
AllowTcpForwarding no
AllowAgentForwarding no
X11Forwarding no
PasswordAuthentication no
SFTP-User und Verzeichnisse anlegen; entscheidend sind die Rechte des ChrootDirectory:
# Gruppe und User anlegen:
sudo groupadd sftponly
sudo useradd -m -s /usr/sbin/nologin -G sftponly webkunde1
sudo passwd webkunde1
# ChrootDirectory anlegen – MUSS root:root / 755 sein:
sudo mkdir -p /srv/sftp/webkunde1
sudo chown root:root /srv/sftp/webkunde1
sudo chmod 755 /srv/sftp/webkunde1
# Upload-Unterverzeichnis für den User (hier darf er schreiben):
sudo mkdir -p /srv/sftp/webkunde1/upload
sudo chown webkunde1:sftponly /srv/sftp/webkunde1/upload
sudo chmod 775 /srv/sftp/webkunde1/upload
Verifizieren: sudo sshd -T -C user=webkunde1,host=test,addr=203.0.113.5 | grep -E 'forcecommand|chrootdirectory|authenticationmethods' zeigt internal-sftp, /srv/sftp/webkunde1 und any.
Schritt 6: Konfiguration prüfen und Dienst graceful neu laden
Dieser Schritt ist der kritischste. Schließen Sie die aktuelle SSH-Sitzung nicht. Öffnen Sie vor dem Neuladen ein zweites Fenster mit einer weiteren Verbindung.
# 1. Syntaxprüfung:
sudo sshd -t
# 2. Effektive Konfiguration kontrollieren:
sudo sshd -T | grep -E 'kexalgorithms|ciphers|macs|hostkeyalgorithms|maxauthtries|passwordauthentication'
# 3. Match-Block für spezifischen User testen:
sudo sshd -T -C user=webkunde1,host=test,addr=203.0.113.5 | grep -E 'forcecommand|chrootdirectory|passwordauthentication'
# 4. Reload, laufende Verbindungen bleiben aktiv (Debian/Ubuntu: Dienst "ssh", RHEL: "sshd"):
sudo systemctl reload ssh
# 5. Status prüfen:
sudo systemctl status ssh
Verbinden Sie sich im zweiten Fenster neu. Schließen Sie die alte Sitzung erst nach erfolgreichem Login.
Verifizieren: Die neue Anmeldung per Schlüssel gelingt; ssh -o PubkeyAuthentication=no user@server endet mit „Permission denied (publickey)“.
Schritt 7: Verifikation mit ssh-audit (Ziel: Grade A)
Prüfen Sie nach dem Reload das Ergebnis:
# Vollständiger Audit-Lauf:
ssh-audit localhost
# Erwartetes Ergebnis (Auszug):
# (kex) sntrup761x25519-sha512@openssh.com
# (kex) curve25519-sha256
# (enc) chacha20-poly1305@openssh.com
# (mac) hmac-sha2-512-etm@openssh.com
# keine Zeile mit [fail]; [warn] höchstens bei bewusst behaltenen Fallbacks
# JSON-Ausgabe für Dokumentation:
ssh-audit -j localhost > /var/log/ssh-audit-$(date +%Y%m%d).json
# Baseline-Policy erstellen (für spätere Vergleiche nach Updates):
ssh-audit -M /etc/ssh/ssh-audit-policy.txt localhost
# Policy-Prüfung nach einem OpenSSH-Update:
ssh-audit -P /etc/ssh/ssh-audit-policy.txt localhost
Verifizieren: ssh-audit localhost | grep -c '\[fail\]' liefert 0, und ssh-audit -P meldet „Passed“.
Algorithmen-Übersicht 2025/2026
| Kategorie | Empfohlen ✓ | Abgelehnt ✗ |
|---|---|---|
| Key Exchange | mlkem768x25519-sha256, sntrup761x25519-sha512, curve25519-sha256, dh-group18-sha512, dh-group16-sha512 | diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256 |
| Ciphers | chacha20-poly1305, aes256-gcm, aes128-gcm, aes256-ctr | arcfour, 3des-cbc, aes128-cbc, aes192-cbc, aes256-cbc |
| MACs | hmac-sha2-512-etm, hmac-sha2-256-etm, umac-128-etm | hmac-md5, hmac-sha1, umac-64 (nicht ETM) |
| HostKey | ssh-ed25519, rsa-sha2-512, rsa-sha2-256 | ssh-rsa (SHA-1), ecdsa-sha2-nistp256/384/521 |
OpenSSH-Versionen und Feature-Verfügbarkeit
| Distribution | OpenSSH-Version | sntrup761x25519 | mlkem768x25519 |
|---|---|---|---|
| Ubuntu 22.04 LTS | 8.9 | ja (@openssh.com) | nein (ab 9.9) |
| Debian 12 | 9.2 | ja | nein (ab 9.9) |
| Ubuntu 24.04 LTS | 9.6 | ja | nein (ab 9.9) |
| RHEL 9 | 8.7 | nein | nein |
| OpenSSH 10.0+ (April 2025) | 10.0 | ja | ja (Standard) |
Version prüfen mit ssh -V. Unter OpenSSH vor 9.9 (Ubuntu 22.04/24.04, Debian 12, RHEL 9) entfernen Sie mlkem768x25519-sha256 aus der KexAlgorithms-Zeile, sonst meldet sshd -t einen Fehler.
Troubleshooting / Typische Fehler
- „Unable to negotiate: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1“ – Alter Client (Switches, alte Java-Bibliotheken) kennt nur schwache KEX-Algorithmen. Einmalig:
ssh -oKexAlgorithms=+diffie-hellman-group14-sha1 user@legacyhost. Dauerhaft: Match-Block mit erweitertem KexAlgorithms für dessen IP. - „bad ownership or modes for chroot directory“ – Prüfen:
ls -ld /srv /srv/sftp /srv/sftp/webkunde1. Alle Verzeichnisse bis zum ChrootDirectory müssenroot:rootundchmod 755(oder 750) sein. - „no matching host key type found. Their offer: ecdsa-sha2-nistp256“ – Der Client hat einen alten ECDSA-Eintrag im known_hosts. Lösung:
ssh-keyscan -H <server> >> ~/.ssh/known_hostsoder alten Eintrag aus~/.ssh/known_hostslöschen. - sshd -T zeigt andere Werte als erwartet – Eine andere Datei setzt dieselbe Direktive früher. Suchen:
grep -r KexAlgorithms /etc/ssh/ - Passwort-Auth im SFTP-Match-Block greift nicht – „Permission denied (publickey)“ trotz gesetztem Passwort. Ursache meist das globale
AuthenticationMethods publickey. Lösung:AuthenticationMethods anyim Match-Block; Diagnose:sudo sshd -T -C user=webkunde1,host=test,addr=203.0.113.5 | grep -E 'passwordauth|authenticationmethods'. - „Subsystem 'sftp' already defined“ bei
sshd -t– Subsystem steht im Drop-in und in der Hauptdatei. OpenSSH vor 9.5 bricht dann ab. Lösung: Zeile aus dem Drop-in entfernen. - Nach moduli-Filter kein DH-Group-Exchange mehr möglich – Filter hat alle Einträge entfernt. Falls
wc -l /etc/ssh/moduli0 liefert:/etc/ssh/moduli.bakzurückkopieren und Filter erneut anwenden. - mlkem768x25519-sha256 unbekannt / sshd -t Fehler – Erst ab OpenSSH 9.9 verfügbar (
ssh -V). Aus der KexAlgorithms-Zeile entfernen.
Häufige Fragen
Welche OpenSSH-Version brauche ich mindestens?
Für sntrup761x25519-sha512@openssh.com OpenSSH 8.5 (Standard seit 9.0; der Name ohne @openssh.com erst ab 9.9). Für mlkem768x25519-sha256 OpenSSH 9.9, Ubuntu 24.04 mit 9.6 also noch nicht. Unbekannte Algorithmennamen weist sshd -t mit „Bad SSH2 KexAlgorithms“ zurück.
Muss ich die Hauptdatei /etc/ssh/sshd_config anfassen?
Nein, nur die Include-Zeile prüfen (Schritt 4). Aktuelle Ubuntu-, Debian- und RHEL-9-Pakete bringen sie mit.
Was prüft ssh-audit und was nicht?
Es prüft Algorithmen, OpenSSH-Version, Banner, bekannte CVEs und DH-Moduli, also nur den Handshake. Nicht geprüft werden Firewall, Fail2ban, Anmeldemethoden und Match-Blöcke.
Warum reicht ein Port-Wechsel von 22 nicht aus?
Ein anderer Port reduziert nur das Rauschen in den Logs; ein Portscan findet ihn in Sekunden. Schutz bieten kryptografische Härtung, Schlüssel-Authentifizierung, MaxAuthTries und ergänzend fail2ban und UFW.
Wie verhindere ich, dass mich ein Tippfehler aussperrt?
sshd -t vor jedem Reload, reload statt restart, zweite Sitzung offen lassen (Schritt 6) und den Konsolenzugang des Hosters vorab testen.
Ist post-quantum Key-Exchange bereits FIPS-zertifiziert?
Nein, sntrup761x25519-sha512 ist nicht FIPS-zertifiziert. Für FIPS-Compliance-Umgebungen verwenden Sie vorerst nur curve25519-sha256 und die DH-Group-16/18-Algorithmen.
Fazit
Die Drop-in-Struktur unter /etc/ssh/sshd_config.d/ lässt die Hauptdatei unangetastet und übersteht Paket-Updates. Nach jedem OpenSSH-Update prüfen Sie mit ssh-audit -P gegen die gespeicherte Policy. Ergänzen Sie das SSH-Hardening mit UFW-Firewall und fail2ban sowie einer Zwei-Faktor-Authentifizierung für besonders exponierte Systeme.
Weiterführende Anleitungen und Quellen
- SSH-Key-Authentifizierung einrichten (Linux & Windows)
- Linux-Server absichern mit UFW und fail2ban
- Zwei-Faktor-Authentifizierung (2FA/MFA) einführen
- Linux-Benutzer, Gruppen, Rechte: chmod, chown und sudo
Quellen: OpenSSH Post-Quantum Cryptography · ssh-audit Hardening Guides · ssh-audit GitHub (jtesta) · Post-Quantum Security for SSH on GitHub · OpenSSH Legacy Options


