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

SSH-Hardening Deep-Dive: sshd_config, Match-Blöcke und ssh-audit für KMU-Server

Vollständig kommentierte sshd_config 2025/2026 für KMU-Server: post-quantum Key-Exchange, CIS-konforme Timeouts, Match-Blöcke für SFTP-only-User, Verifikation mit ssh-audit (Grade A) – Schritt für Schritt ohne Aussperr-Risiko.

Server-Rack mit blauen LED-Lichtern und holografischen Schloss-Symbolen als Metapher für SSH-Hardening

Ein offen erreichbarer SSH-Dienst ist das Einfallstor Nummer eins auf KMU-Servern – und gleichzeitig das am häufigsten halbherzig gehärtete Protokoll. OpenSSH bringt von Haus aus moderate Standardeinstellungen mit, die jedoch keineswegs für den Produktionsbetrieb ausreichen: veraltete Diffie-Hellman-Gruppen, keine explizite Algorithmus-Whitelist, fehlende Timeouts. Diese Anleitung zeigt dir, wie du auf Ubuntu 22.04/24.04, Debian 12 oder RHEL 9/10 eine vollständig kommentierte, wartbare Drop-in-Konfiguration erstellst, Match-Blöcke für SFTP-only-User und Admin-Netze einrichtest und das Ergebnis mit ssh-audit auf Grade A verifizierst – ohne dich dabei auszusperren.

Voraussetzungen

  • Server mit Ubuntu 22.04/24.04 LTS, Debian 12 oder RHEL 9/10 – OpenSSH >= 8.9 empfohlen, >= 9.0 für sntrup761x25519
  • 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
  • Bestehende Ed25519-SSH-Schlüssel für alle Admin-Benutzer – nach dem Hardening ist Passwort-Auth deaktiviert
  • Backup der aktuellen Konfiguration: sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
  • Python 3.9+ auf dem Audit-System (für ssh-audit via pip) oder direktes apt-Paket
  • Für SFTP-Nutzer: geplante Benutzerkonten, Gruppen und Verzeichnisstruktur

Schritt 1: ssh-audit installieren und Ist-Zustand erfassen

Bevor du irgendetwas änderst, dokumentierst du den aktuellen Zustand. ssh-audit analysiert den SSH-Handshake und listet alle angebotenen Algorithmen mit Bewertung auf – ohne sich einzuloggen, rein passiv.

# Installation auf Debian/Ubuntu:
sudo apt install ssh-audit

# Alternativ via pip (immer aktuelle Version):
pip3 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\]|Grade'

# Eingebaute Härtungsanleitungen auflisten:
ssh-audit --list-hardening-guides

# Härtungsanleitung für Ubuntu 24.04 LTS abrufen:
ssh-audit --get-hardening-guide ubuntu_2404_lts

Die Ausgabe enthält Bewertungen: [fail] = kritisch, [warn] = schwach, [info] = neutral, [ok] = bestanden. Der Grade (A–F) und der Score (0–100) zeigen den Gesamtstatus. Auf einem frischen Ubuntu-Server wirst du typischerweise Grade C oder D sehen – das ist normal und der Ausgangspunkt dieser Anleitung.

Schritt 2: Moduli-Datei filtern

Die Datei /etc/ssh/moduli enthält vordefinierte DH-Gruppen. Schwache Gruppen (unter 4096 Bit) solltest du entfernen, bevor du diffie-hellman-group-exchange-sha256 anbietest.

# Nur Einträge mit Bitlänge > 4095 behalten:
awk '$5 > 4095' /etc/ssh/moduli > /etc/ssh/moduli.safe
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. Sollte das passieren, installiere das Paket openssh-server neu, um eine frische moduli-Datei zu erhalten, und wende den Filter erneut an.

Schritt 3: Host-Keys prüfen und ggf. neu generieren

Das Hardening beschränkt HostKeyAlgorithms auf Ed25519 und RSA/SHA-2. Falls noch kein Ed25519-Hostkey vorhanden ist, generierst du ihn jetzt.

# 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

Schritt 4: Drop-in-Härtungskonfiguration anlegen

Aktuelle Ubuntu-, Debian- und RHEL-9-Pakete laden automatisch alle /etc/ssh/sshd_config.d/*.conf ein. Prüfe zunächst, ob die Include-Direktive in der Hauptdatei vorhanden ist:

grep 'Include' /etc/ssh/sshd_config
# Erwartete Ausgabe: Include /etc/ssh/sshd_config.d/*.conf

# Falls die Zeile fehlt, füge sie ganz oben ein:
# sudo sed -i '1s/^/Include \/etc\/ssh\/sshd_config.d\/*.conf\n/' /etc/ssh/sshd_config

Nun legst du die eigentliche Härtungsdatei an. Die Nummerierung „10" stellt sicher, dass diese Datei vor eventuellen Ausnahme-Dateien geladen wird – denn 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)
#   -> nur verfügbar ab OpenSSH 9.9 (Ubuntu 24.04+); auf Ubuntu 22.04 weglassen!
# sntrup761x25519 = Hybrid post-quantum (NTRU Prime + X25519), seit OpenSSH 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 (OpenSSH-intern) ---
Subsystem sftp internal-sftp -f AUTHPRIV -l INFO

Lege die Datei mit sudo tee an und prüfe anschließend 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'

Schritt 5: Match-Blöcke für Admin-Netze und SFTP-only-User

Match-Blöcke müssen zwingend am Ende der Konfiguration stehen. Durch eine separate Datei mit hoher Nummer (90) stellst du sicher, dass sie nach allen globalen Direktiven geladen wird.

# 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!
Match Group sftponly
  ForceCommand internal-sftp -l INFO
  ChrootDirectory /srv/sftp/%u
  AllowTcpForwarding no
  AllowAgentForwarding no
  X11Forwarding no
  PasswordAuthentication yes

# === Match-Block: einzelner Backup-User ===
Match User backupuser
  ForceCommand internal-sftp
  ChrootDirectory /backup/sftp
  AllowTcpForwarding no
  AllowAgentForwarding no
  X11Forwarding no
  PasswordAuthentication no

SFTP-User anlegen und Verzeichnisstruktur vorbereiten – die ChrootDirectory-Rechte sind entscheidend:

# 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

Schritt 6: Konfiguration prüfen und Dienst graceful neu laden

Dieser Schritt ist der kritischste. Schließe die aktuelle SSH-Sitzung NICHT – öffne stattdessen ein zweites Fenster mit einer weiteren Verbindung, bevor du den Dienst neu lädst.

# 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 | grep -E 'forcecommand|chrootdirectory|passwordauthentication'

# 4. Graceful Reload (laufende Verbindungen bleiben aktiv!):
sudo systemctl reload sshd

# 5. Status prüfen:
sudo systemctl status sshd

Verbinde dich jetzt mit dem zweiten Fenster neu. Erst wenn der Login erfolgreich ist, darfst du die alte Sitzung schließen.

Schritt 7: Verifikation mit ssh-audit (Ziel: Grade A)

Nach erfolgreichem Reload prüfst du das Ergebnis:

# Vollständiger Audit-Lauf:
ssh-audit localhost

# Erwartetes Ergebnis:
# (ok) kex: mlkem768x25519-sha256
# (ok) kex: sntrup761x25519-sha512@openssh.com
# (ok) enc: chacha20-poly1305@openssh.com
# (ok) mac: hmac-sha2-512-etm@openssh.com
# Grade: A   Score: 100 / 100

# 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

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.9nein (ab 9.0)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)

Versionscheck vor dem Setzen von mlkem768x25519: ssh -V. Auf Ubuntu 22.04 (OpenSSH 8.9) entfernst du mlkem768x25519-sha256 aus der KexAlgorithms-Zeile – sshd -t meldet sonst einen Fehler.

Troubleshooting / Typische Fehler

  • „Unable to negotiate: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1" – Ein alter Client (Cisco-Switches, WinSCP < 5.x, alte Java-Clients) unterstützt nur schwache KEX-Algorithmen. Diagnose: ssh -vvv user@server. Einmalig: ssh -oKexAlgorithms=+diffie-hellman-group14-sha1 user@legacyhost. Dauerlösung: Match-Block mit erweitertem KexAlgorithms für die IP des Legacy-Systems anlegen.
  • „bad ownership or modes for chroot directory" – Das ChrootDirectory oder einer seiner Pfadanteile ist nicht root:root oder hat Schreibrechte für andere. Prüfen: ls -la /srv/sftp/. 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 Drop-in-Datei oder die Hauptkonfiguration hat dieselbe Direktive früher gesetzt. Ersten Treffer finden: sudo sshd -T | grep kexalgorithms. Alle Drop-ins auf Konflikte prüfen: grep -r KexAlgorithms /etc/ssh/
  • Passwort-Auth im SFTP-Match-Block greift nicht – SFTP-User erhält „Permission denied (publickey)" obwohl Passwort gesetzt. Diagnose: sudo sshd -T -C user=webkunde1 | grep passwordauthentication – zeigt, ob der Match-Block tatsächlich aktiv ist.
  • Nach moduli-Filter kein DH-Group-Exchange mehr möglich – Zu aggressiver Filter hat alle Einträge entfernt. Prüfen: wc -l /etc/ssh/moduli. Falls leer: sudo apt install --reinstall openssh-server und Filter erneut anwenden.
  • mlkem768x25519-sha256 unbekannt / sshd -t Fehler – Algorithmus erst ab OpenSSH 9.9 verfügbar. Versionscheck: ssh -V. Algorithmus aus KexAlgorithms-Zeile entfernen, falls OpenSSH < 9.9.

Häufige Fragen

Welche OpenSSH-Version brauche ich mindestens?

Für sntrup761x25519-sha512: OpenSSH >= 9.0 (Debian 12, Ubuntu 22.04 hat 8.9 – dort weglassen). Für mlkem768x25519-sha256: OpenSSH >= 9.9 (Ubuntu 24.04 hat 9.6 – dort ebenfalls weglassen). Versionscheck: ssh -V. sshd -t prüft Syntax, aber nicht ob Algorithmen zur Laufzeit verfügbar sind – ein Laufzeitfehler erscheint erst beim Verbindungsaufbau.

Muss ich die Hauptdatei /etc/ssh/sshd_config anfassen?

Nur prüfen, ob die Include-Direktive vorhanden ist: grep Include /etc/ssh/sshd_config. Aktuelle Ubuntu-, Debian- und RHEL-9-Pakete haben Include /etc/ssh/sshd_config.d/*.conf standardmäßig als erste nicht-kommentierte Zeile. Falls sie fehlt, muss sie ganz oben ergänzt werden.

Was prüft ssh-audit und was nicht?

ssh-audit prüft: unterstützte KEX/Cipher/MAC/HostKey-Algorithmen, OpenSSH-Version, Banner, bekannte CVEs, DH-Moduli-Qualität. Es prüft nicht: Firewall-Regeln, fail2ban-Konfiguration, ob PasswordAuthentication tatsächlich deaktiviert ist (nur was der Server im Handshake anbietet) oder Match-Block-Logik. Für ein vollständiges Audit müssen diese Punkte separat geprüft werden.

Warum reicht ein Port-Wechsel von 22 nicht aus?

Ein Port-Wechsel ist „Security by Obscurity" und reduziert lediglich Brute-Force-Noise in den Logs. Ein gezielter Angreifer findet offene Ports per nmap in Sekunden. Echter Schutz kommt durch kryptografische Härtung, Schlüssel-Authentifizierung, MaxAuthTries und ergänzend fail2ban und UFW.

Wie verhindere ich, dass mich ein Tippfehler aussperrt?

Drei Sicherheitsnetze: (1) sshd -t vor dem Reload ausführen (Syntaxfehler erkennen), (2) systemctl reload statt restart nutzen (laufende Verbindungen bleiben aktiv), (3) eine zweite SSH-Sitzung im selben Terminal offen lassen, bis der Login mit der neuen Konfiguration bestätigt ist. Bei Cloud-VMs: Konsolen-Zugang (KVM/VNC) als Notfall-Fallback prüfen.

Ist post-quantum Key-Exchange bereits FIPS-zertifiziert?

Noch nicht vollständig: sntrup761x25519-sha512 ist bisher nicht FIPS-zertifiziert. GitHub.com rollt den Algorithmus seit September 2025 weltweit aus, jedoch sind FIPS-Regionen (USA, Behörden) noch ausgenommen. Für FIPS-Compliance-Umgebungen verwendest du vorerst nur curve25519-sha256 und die DH-Group-16/18-Algorithmen.

Fazit

SSH-Hardening ist kein einmaliger Eingriff, sondern ein Prozess: Algorithmen-Whitelist setzen, Timeouts und Auth-Limits nach CIS-Benchmark konfigurieren, Match-Blöcke für spezifische Anwendungsfälle anlegen und das Ergebnis regelmäßig mit ssh-audit verifizieren. Die Drop-in-Struktur unter /etc/ssh/sshd_config.d/ macht die Konfiguration wartbar und sicher – Hauptdatei bleibt unangetastet, Ausnahmen kommen in nummerierte Dateien mit hoher Priorität. Nach einem OpenSSH-Update lohnt sich ein erneuter ssh-audit -P-Lauf gegen die gespeicherte Policy, um neu eingeführte Algorithmen zu evaluieren. Ergänze 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