SSH-Härtung

1. Einführung – Warum SSH-Härtung?

SSH (Secure Shell) ist das meistgenutzte Protokoll zur Fernverwaltung von Linux- und Unix-Systemen. Genau deshalb ist es auch eines der bevorzugten Angriffsziele im Internet. Wer einen Server mit öffentlich erreichbarem SSH-Port betreibt, kann in den Log-Dateien innerhalb weniger Stunden Tausende von fehlgeschlagenen Anmeldeversuchen beobachten. Diese Angriffe laufen vollautomatisch ab: Botnetze scannen kontinuierlich den gesamten IPv4-Adressraum nach offenem Port 22 und probieren anschließend massenhaft Benutzername-Passwort-Kombinationen durch.

Zwei Angriffsmethoden dominieren dabei: Brute-Force-Angriffe, bei denen systematisch alle möglichen Passwörter ausprobiert werden, und Credential Stuffing, bei dem geleakte Zugangsdaten aus anderen Datenpannen direkt gegen SSH-Server getestet werden. Letzteres ist besonders gefährlich, weil viele Nutzer identische Passwörter auf mehreren Diensten verwenden.

Die gute Nachricht: Mit einer konsequenten Härtung des SSH-Dienstes lässt sich das Angriffspotenzial drastisch reduzieren. Die meisten Maßnahmen sind in wenigen Minuten umgesetzt und erfordern kein tiefes Sicherheitswissen. Dieser Artikel führt Schritt für Schritt durch die wichtigsten Härtungsmaßnahmen – von der sshd_config über fail2ban bis hin zu fortgeschrittenen Techniken wie Port Knocking und SSH-Zertifikaten.

Wichtiger Hinweis: Bevor Änderungen an der SSH-Konfiguration vorgenommen werden, sollte immer eine zweite SSH-Sitzung geöffnet bleiben, um bei Konfigurationsfehlern nicht ausgesperrt zu werden. Außerdem empfiehlt sich ein Test mit sshd -t vor dem Neustart des Dienstes, um Syntaxfehler zu erkennen.

2. Schlüsseltypen und Key-Management

Die sicherste Authentifizierungsmethode für SSH ist die Public-Key-Authentifizierung. Anstelle eines Passworts wird ein kryptografisches Schlüsselpaar verwendet: Der private Schlüssel verbleibt auf dem Client, der öffentliche Schlüssel wird auf dem Server hinterlegt. Ein Angreifer, der das Passwort kennt, kommt damit nicht weiter – er benötigt zusätzlich den privaten Schlüssel.

2.1 RSA vs. Ed25519

Aktuell sind zwei Schlüsseltypen für neue Schlüsselpaare empfehlenswert:

  • Ed25519 ist der bevorzugte Algorithmus. Er basiert auf elliptischen Kurven (Edwards-curve Digital Signature Algorithm) und bietet bei sehr kurzen Schlüsseln (256 Bit) eine hohe Sicherheit, schnelle Operationen und Resistenz gegen bestimmte Seitenkanalangriffe. Ed25519 wird von allen modernen SSH-Implementierungen unterstützt.
  • RSA ist weit verbreitet und kompatibel mit älteren Systemen. Für RSA gilt heute eine Mindestlänge von 4096 Bit. Schlüssel mit 1024 oder 2048 Bit gelten als veraltet und sollten ersetzt werden. RSA-Schlüssel sind deutlich größer als Ed25519-Schlüssel bei vergleichbarer oder geringerer Sicherheit.
  • ECDSA (Elliptic Curve DSA) ist ebenfalls verfügbar, wird aber gegenüber Ed25519 nicht bevorzugt, da Ed25519 eine sicherere Kurve verwendet.

2.2 Schlüssel generieren

Ein neues Ed25519-Schlüsselpaar wird auf dem Client mit folgendem Befehl erzeugt:

# Ed25519 (empfohlen)
ssh-keygen -t ed25519 -C "kommentar@beispiel.de"

# RSA mit 4096 Bit (für Kompatibilität mit älteren Systemen)
ssh-keygen -t rsa -b 4096 -C "kommentar@beispiel.de"

Der Befehl fragt nach einem Speicherort (Standard: ~/.ssh/id_ed25519) und einer Passphrase. Die Passphrase schützt den privaten Schlüssel zusätzlich, falls die Schlüsseldatei in falsche Hände gerät. Sie sollte nie leer gelassen werden.

2.3 Öffentlichen Schlüssel auf den Server übertragen

# Komfortabler Weg mit ssh-copy-id
ssh-copy-id -i ~/.ssh/id_ed25519.pub benutzer@server

# Manueller Weg
cat ~/.ssh/id_ed25519.pub | ssh benutzer@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

2.4 authorized_keys verwalten

Die Datei ~/.ssh/authorized_keys enthält alle erlaubten öffentlichen Schlüssel, einen pro Zeile. Wichtig sind korrekte Berechtigungen – ohne diese verweigert OpenSSH den Zugang aus Sicherheitsgründen:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Nicht mehr benötigte Schlüssel sollten regelmäßig aus der Datei entfernt werden. In größeren Umgebungen empfiehlt sich der Einsatz von SSH-Zertifikaten (siehe Abschnitt 6), um das Key-Management zu zentralisieren.

3. sshd_config härten

Die Hauptkonfigurationsdatei des SSH-Daemons liegt unter /etc/ssh/sshd_config. Nach jeder Änderung muss der SSH-Dienst neu geladen werden:

# Konfiguration auf Syntaxfehler prüfen
sudo sshd -t

# Dienst neu laden (ohne bestehende Verbindungen zu trennen)
sudo systemctl reload sshd

3.1 Passwort-Authentifizierung deaktivieren

Sobald die Public-Key-Authentifizierung funktioniert, sollte die Passwort-Authentifizierung vollständig deaktiviert werden. Das eliminiert Brute-Force- und Credential-Stuffing-Angriffe auf einen Schlag.

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

3.2 Root-Login verbieten

Der direkte Login als root über SSH sollte grundsätzlich verboten sein. Administratoren melden sich als normaler Benutzer an und wechseln bei Bedarf mit sudo oder su zu erhöhten Rechten.

PermitRootLogin no

Falls root-Zugang zwingend benötigt wird (z. B. für automatisierte Deployments), kann alternativ PermitRootLogin prohibit-password gesetzt werden. Damit ist nur Key-basierter root-Login erlaubt, aber keine Passwort-Anmeldung.

3.3 Erlaubte Benutzer und Gruppen einschränken

Mit AllowUsers und AllowGroups lässt sich festlegen, welche Konten sich überhaupt per SSH anmelden dürfen. Alle anderen Konten werden pauschal abgewiesen, selbst wenn die Authentifizierung erfolgreich wäre.

# Nur bestimmte Benutzer erlauben
AllowUsers alice bob deploy

# Oder: Nur Mitglieder einer bestimmten Gruppe erlauben
AllowGroups sshusers

3.4 Port ändern

Den SSH-Port von 22 auf einen anderen Wert zu setzen, ist eine Maßnahme der "Security through Obscurity" und ersetzt keine echte Sicherheit. Sie reduziert jedoch den automatisierten Scan-Traffic erheblich, da die meisten Bots ausschließlich Port 22 scannen. Ein Port im Bereich 1024–65535 ist üblich.

Port 2222

Achtung: Firewalls und ggf. SELinux/AppArmor müssen angepasst werden. Der neue Port muss in der Firewall freigegeben und der alte gesperrt werden.

# UFW-Beispiel
sudo ufw allow 2222/tcp
sudo ufw deny 22/tcp

3.5 Anmeldeversuche und Timeout begrenzen

# Maximale Fehlversuche pro Verbindung
MaxAuthTries 3

# Zeitfenster für einen Anmeldevorgang in Sekunden
LoginGraceTime 30

# Maximale gleichzeitige nicht-authentifizierte Verbindungen
MaxStartups 10:30:60

MaxStartups 10:30:60 bedeutet: Ab 10 offenen, nicht-authentifizierten Verbindungen werden 30 % der neuen Verbindungen zufällig abgelehnt; ab 60 werden alle abgelehnt. Das erschwert parallele Angriffe erheblich.

3.6 Protokollversion erzwingen

SSH Protocol 1 gilt als unsicher und sollte nie verwendet werden. Moderne OpenSSH-Versionen unterstützen ausschließlich Protocol 2 – zur Sicherheit kann dies explizit erzwungen werden:

Protocol 2

3.7 Starke Kryptografie erzwingen

Mit den Direktiven Ciphers, MACs und KexAlgorithms können veraltete und schwache Algorithmen ausgeschlossen werden. Die folgende Konfiguration erlaubt nur moderne, als sicher geltende Algorithmen:

# Nur starke symmetrische Verschlüsselungsverfahren
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# Nur starke MAC-Algorithmen
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

# Nur starke Schlüsselaustauschverfahren
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512

Welche Algorithmen der eigene OpenSSH-Server unterstützt, lässt sich mit ssh -Q cipher, ssh -Q mac und ssh -Q kex abfragen.

3.8 Weitere sinnvolle Einstellungen

# X11-Weiterleitung deaktivieren (sofern nicht benötigt)
X11Forwarding no

# TCP-Weiterleitung deaktivieren (sofern nicht benötigt)
AllowTcpForwarding no

# Agent-Weiterleitung deaktivieren
AllowAgentForwarding no

# SSH-Banner anzeigen (optionaler Hinweis auf unbefugten Zugriff)
Banner /etc/ssh/banner.txt

# Leerlauf-Timeout: Verbindung nach 5 Minuten Inaktivität trennen
ClientAliveInterval 300
ClientAliveCountMax 2

4. Zwei-Faktor-Authentifizierung

Auch wenn Public-Key-Authentifizierung bereits sehr sicher ist, lässt sich mit einem zweiten Faktor (TOTP – Time-based One-Time Password) die Sicherheit weiter erhöhen. Selbst ein kompromittierter privater Schlüssel reicht dann allein nicht mehr aus. Die Integration erfolgt über das PAM-Modul libpam-google-authenticator, das TOTP-fähige Apps wie Google Authenticator, Aegis oder Authy unterstützt.

4.1 libpam-google-authenticator installieren

sudo apt install libpam-google-authenticator

4.2 TOTP für einen Benutzer einrichten

Als der betreffende Benutzer (nicht als root) wird das Setup-Tool ausgeführt:

google-authenticator

Das Tool generiert einen QR-Code, der mit einer Authenticator-App gescannt wird. Zusätzlich werden Notfall-Codes ausgegeben für den Fall, dass das zweite Gerät nicht verfügbar ist. Diese Codes müssen sicher aufbewahrt werden, da jeder Code nur einmal verwendbar ist.

4.3 PAM konfigurieren

In /etc/pam.d/sshd wird die Google-Authenticator-Integration aktiviert. Die Zeile wird am Ende der Datei hinzugefügt:

auth required pam_google_authenticator.so

4.4 sshd_config anpassen

ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

Mit AuthenticationMethods publickey,keyboard-interactive müssen beide Faktoren erfolgreich sein: zuerst der SSH-Key, danach der TOTP-Code. Wer nur TOTP ohne Key erzwingen möchte, setzt stattdessen AuthenticationMethods keyboard-interactive. Nach der Konfigurationsänderung den SSH-Dienst neu laden und die Funktion mit einer neuen Verbindung testen, bevor die aktuelle Sitzung beendet wird.

5. fail2ban einrichten

fail2ban überwacht Log-Dateien auf verdächtige Muster und sperrt automatisch IP-Adressen, die zu viele fehlgeschlagene Anmeldeversuche produzieren. Damit wird Brute-Force-Traffic auf Netzwerkebene geblockt, bevor er den SSH-Daemon überhaupt erreicht.

5.1 Installation

sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

5.2 Konfiguration über jail.local

Die Standardkonfiguration liegt in /etc/fail2ban/jail.conf. Eigene Anpassungen gehören ausschließlich in /etc/fail2ban/jail.local, damit sie bei Paket-Updates nicht überschrieben werden:

[DEFAULT]
# Standard-Banzeit: 1 Stunde
bantime = 3600

# Beobachtungszeitraum: 10 Minuten
findtime = 600

# Erlaubte Fehlversuche im Beobachtungszeitraum
maxretry = 5

# Backend für Log-Überwachung
backend = systemd

# Eigene IP-Adressen niemals sperren (Whitelist)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400

5.3 fail2ban verwalten

# Status aller Jails anzeigen
sudo fail2ban-client status

# Status des SSH-Jails
sudo fail2ban-client status sshd

# Eine gesperrte IP manuell freigeben
sudo fail2ban-client set sshd unbanip 203.0.113.42

# Eine IP manuell sperren
sudo fail2ban-client set sshd banip 203.0.113.42

5.4 Progressive Banzeiten

Für Systeme mit hohem Angriffsaufkommen empfiehlt sich eine progressiv ansteigende Banzeit. fail2ban unterstützt dies ab Version 0.10 mit der Option bantime.increment. Wiederholte Angreifer werden damit exponentiell länger gesperrt:

[DEFAULT]
bantime.increment = true
bantime.factor = 1
bantime.multiplier = 24
bantime.maxtime = 604800

6. Weitere Maßnahmen

6.1 Port Knocking mit knockd

Port Knocking ist eine Technik, bei der der SSH-Port standardmäßig durch die Firewall gesperrt ist und erst nach einer bestimmten Sequenz von Verbindungsversuchen auf definierten Ports geöffnet wird. Ohne die korrekte Klopfsequenz ist der SSH-Port für außen vollständig unsichtbar – auch ein Portscan zeigt keinen offenen Port.

sudo apt install knockd

Konfiguration in /etc/knockd.conf:

[options]
    UseSyslog

[openSSH]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn

Der Client öffnet den Port mit knock server 7000 8000 9000 und schließt ihn nach der Sitzung wieder mit der umgekehrten Sequenz. Port Knocking bietet keinen absoluten Schutz – die Sequenz kann bei unverschlüsseltem Netzwerktraffic mitgeschnitten werden –, erschwert jedoch automatisiertes Scanning erheblich.

6.2 SSH-Zertifikate für skalierbare Umgebungen

In größeren Umgebungen mit vielen Servern und Benutzern wird das Verwalten von authorized_keys-Dateien schnell unübersichtlich. Jeder neue Server benötigt die Schlüssel aller Benutzer, und beim Entfernen eines Benutzers müssen alle Server einzeln aktualisiert werden.

SSH-Zertifikate schaffen Abhilfe: Eine zentrale Certificate Authority (CA) signiert Benutzerschlüssel, und Server vertrauen pauschal allen Schlüsseln, die von dieser CA signiert wurden. Das ermöglicht zentrales Benutzer-Management ohne manuelle Key-Distribution. Zusätzlich können Zertifikate mit einer Gültigkeitsdauer versehen werden.

# CA-Schlüsselpaar generieren (einmalig, sicher aufbewahren)
ssh-keygen -t ed25519 -f /etc/ssh/ssh_ca -C "SSH CA"

# Benutzerschlüssel signieren (gültig für 1 Tag, Principals: erlaubte Benutzernamen)
ssh-keygen -s /etc/ssh/ssh_ca -I "alice@company" -n alice -V +1d ~/.ssh/id_ed25519.pub

# In sshd_config auf jedem Server: CA als vertrauenswürdig markieren
TrustedUserCAKeys /etc/ssh/ssh_ca.pub

6.3 SSH-Jumphosts und Bastion Hosts

In sicherheitskritischen Infrastrukturen sind interne Server nicht direkt aus dem Internet erreichbar. Stattdessen läuft der SSH-Zugang ausschließlich über einen dedizierten Bastion Host (auch Jumphost genannt), der stark gehärtet, protokolliert und überwacht ist. Alle anderen Server sind nur innerhalb des internen Netzwerks per SSH erreichbar, was die Angriffsfläche drastisch reduziert.

# SSH-Verbindung über einen Jumphost in ~/.ssh/config konfigurieren
Host interner-server
    HostName 10.0.1.50
    User alice
    ProxyJump bastion.beispiel.de

# Oder direkt auf der Kommandozeile ohne Konfigurationsdatei
ssh -J alice@bastion.beispiel.de alice@10.0.1.50

Der Bastion Host selbst sollte besonders restriktiv konfiguriert sein: kein Passwort-Login, kein Root-Login, fail2ban aktiv, alle nicht benötigten Dienste deaktiviert, und regelmäßige Überprüfung der Zugangslisten.

7. Monitoring und Log-Auswertung

Eine gehärtete SSH-Konfiguration sollte kontinuierlich überwacht werden. Log-Dateien liefern wertvolle Informationen über Angriffsversuche, ungewöhnliche Aktivitäten und erfolgreiche Anmeldungen. Anomalien fallen nur auf, wenn man aktiv hinschaut.

7.1 Wichtige Log-Quellen

# Klassische Syslog-Datei (Debian/Ubuntu)
/var/log/auth.log

# systemd Journal – Echtzeit-Monitoring des SSH-Daemons
sudo journalctl -u sshd -f

# Nur Fehler und Warnungen anzeigen
sudo journalctl -u sshd -p warning

# Letzte fehlgeschlagene Anmeldeversuche (alle Protokolle)
sudo lastb | head -30

# Aktuelle Anmeldungen und letzte erfolgreiche Logins
who
last | head -20

7.2 Brute-Force-Muster erkennen

Typische Brute-Force-Angriffe erzeugen in kurzer Zeit viele Einträge wie Failed password for invalid user root from 203.0.113.42 oder Invalid user admin from 198.51.100.7. Die häufigsten angreifenden IP-Adressen lassen sich mit einfachen Shell-Befehlen schnell identifizieren:

# Top 10 angreifende IPs aus auth.log
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10

# Anzahl fehlgeschlagener Versuche insgesamt am heutigen Tag
grep "Failed password" /var/log/auth.log | grep "$(date '+%b %e')" | wc -l

# Alle verwendeten Benutzernamen bei Angriffen – zeigt gängige Ziele
grep "Invalid user" /var/log/auth.log | awk '{print $8}' | sort | uniq -c | sort -rn | head -20

7.3 Automatisiertes Monitoring mit logwatch

Für professionelle Umgebungen empfiehlt sich der Einsatz von zentralen Log-Management-Lösungen wie dem ELK-Stack (Elasticsearch, Logstash, Kibana), Graylog oder Loki mit Grafana. Diese ermöglichen Dashboards, Alerting bei ungewöhnlichen Anmeldemustern und langfristige Auswertungen über mehrere Server hinweg.

Einfacher und für kleinere Setups ausreichend ist logwatch, das täglich eine Zusammenfassung der Log-Aktivitäten per E-Mail verschickt:

sudo apt install logwatch

Anpassungen in /etc/logwatch/conf/logwatch.conf:

MailTo = admin@beispiel.de
Detail = Med
Range = yesterday

7.4 Sicherheits-Checkliste SSH-Härtung

Als abschließende Zusammenfassung die wichtigsten Punkte auf einen Blick:

  • Public-Key-Authentifizierung aktiviert, Passwort-Login vollständig deaktiviert
  • Ed25519- oder RSA-4096-Schlüssel mit Passphrase verwenden
  • Root-Login verboten (PermitRootLogin no)
  • Erlaubte Benutzer explizit eingeschränkt (AllowUsers oder AllowGroups)
  • Nur starke Cipher, MACs und KexAlgorithmen erlaubt
  • MaxAuthTries und LoginGraceTime auf niedrige Werte reduziert
  • fail2ban installiert und für den SSH-Port konfiguriert
  • SSH-Port ggf. von 22 auf einen ungebräuchlichen Port geändert
  • X11Forwarding und AllowTcpForwarding deaktiviert (sofern nicht benötigt)
  • Inaktivitäts-Timeout mit ClientAliveInterval gesetzt
  • Log-Monitoring eingerichtet und regelmäßige Auswertung sichergestellt
  • authorized_keys-Dateien regelmäßig auf veraltete Einträge prüfen
  • OpenSSH-Paket zeitnah aktualisieren, wenn Sicherheits-Updates erscheinen