Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Linux 04.06.2026 · 10 min Lesezeit

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

Geschlossenes Vorhängeschloss auf einem Rack-Server in einem blau beleuchteten Rechenzentrumsgang

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 pipx oder 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

KategorieEmpfohlen ✓Abgelehnt ✗
Key Exchangemlkem768x25519-sha256, sntrup761x25519-sha512, curve25519-sha256, dh-group18-sha512, dh-group16-sha512diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256
Cipherschacha20-poly1305, aes256-gcm, aes128-gcm, aes256-ctrarcfour, 3des-cbc, aes128-cbc, aes192-cbc, aes256-cbc
MACshmac-sha2-512-etm, hmac-sha2-256-etm, umac-128-etmhmac-md5, hmac-sha1, umac-64 (nicht ETM)
HostKeyssh-ed25519, rsa-sha2-512, rsa-sha2-256ssh-rsa (SHA-1), ecdsa-sha2-nistp256/384/521

OpenSSH-Versionen und Feature-Verfügbarkeit

DistributionOpenSSH-Versionsntrup761x25519mlkem768x25519
Ubuntu 22.04 LTS8.9ja (@openssh.com)nein (ab 9.9)
Debian 129.2janein (ab 9.9)
Ubuntu 24.04 LTS9.6janein (ab 9.9)
RHEL 98.7neinnein
OpenSSH 10.0+ (April 2025)10.0jaja (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üssen root:root und chmod 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_hosts oder alten Eintrag aus ~/.ssh/known_hosts lö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 any im 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/moduli 0 liefert: /etc/ssh/moduli.bak zurü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

Quellen: OpenSSH Post-Quantum Cryptography · ssh-audit Hardening Guides · ssh-audit GitHub (jtesta) · Post-Quantum Security for SSH on GitHub · OpenSSH Legacy Options