SSH-Server

Siehe auch

Verwandte Artikel
Offizielle Dokumentation
Linuxfabrik

Wichtige Eigenschaften von SSH:

  • Authentifizierung der Gegenstelle.

  • Die symmetrische Verschlüsselung der Datenübertragung mit sitzungsabhängigen Schlüsseln erschwert eine Entschlüsselung der Kommunikation durch Dritte massiv.

  • Manipulation der übertragenen Daten wird verhindert und ermöglicht Datenintegrität.

Änderungen an der Konfiguration des SSH-Servers sollten immer in einer zweiten SSH-Session getestet werden, um ein versehentliches Aussperren zu verhindern. In der ersten SSH-Session also Änderungen vornehmen und den SSH-Daemon neu starten, aber Test der Settings, Login, Logout usw. im zweiten Terminal vornehmen.

SSH-Server härten

Die folgenden Einstellungen lassen sich in der /etc/ssh/sshd_config vornehmen, um die Sicherheit je nach Anforderung weiter zu erhöhen oder den SSH-Server anzupassen. Nach Änderung der Einstellungen muss der SSH-Server neu gestartet werden, was auch bei laufender SSH-Session funktioniert.

AllowTcpForwarding no       # prevent malware (and everything else) from tunneling
ClientAliveCountMax 0       # do not send keep-alive messages
ClientAliveInterval 300     # 5 minute idle timeout, then logout
DisableForwarding yes       # CIS: umbrella switch that disables all forwarding types
GSSAPIAuthentication no     # disable GSSAPI unless Kerberos SSO is actually used
HostbasedAuthentication no  # disable .rhosts and /etc/hosts.equiv (SSHv2)
IgnoreRhosts yes            # disable .rhosts and .shosts files
LoginGraceTime 60           # disconnect timeout after failed login
LogLevel VERBOSE            # raise logging (required for fail2ban)
MaxAuthTries 3              # drop connection after N failed auth attempts (default 6)
MaxSessions 4               # max multiplexed sessions per connection
MaxStartups 10:30:60        # concurrent unauthenticated connections (start:rate%:full)
PasswordAuthentication no   # disable password login
PermitEmptyPasswords no     # no empty passwords
PermitRootLogin no          # disable direct root login (keep a sudo-capable user)
PermitUserEnvironment no    # prevent users from setting env vars (PATH etc.)
Port 56669                  # non-standard port - no real security, just less brute force noise
PubkeyAuthentication yes    # allow key-based authentication
UsePAM yes                  # delegate authentication to PAM
X11Forwarding no            # disable X11 tunneling through sshd forwarding

Wer den SSH-Port ändert, muss dies auch per SELinux erlauben:

dnf --assumeyes install policycoreutils-python-utils

semanage port --add --type ssh_port_t --proto tcp 56669

Änderungen an Verschlüsselungsoptionen wie Ciphers, MACs oder KexAlgorithms empfehlen wir nicht direkt in der sshd_config. Stattdessen die systemweite Crypto-Policies konfigurieren, die auch vom SSH-Daemon verwendet wird. Wer aus Compliance-Gründen eine harte Baseline in der sshd_config haben muss (CIS- Benchmark-Profil), kann die in der Mozilla-OpenSSH-Guide hinterlegten Listen übernehmen.

Siehe auch

Weitere CIS-Empfehlungen

Über die obige Baseline hinaus verlangt der CIS-Benchmark für RHEL 10 noch ein paar Hardening-Punkte rund um den SSH-Server, die hier der Vollständigkeit halber erwähnt werden:

Dateiberechtigungen auf sshd_config

/etc/ssh/sshd_config muss root:root gehören und 0600 (bzw. restrictiver) sein. Analog gilt 0644 für Public-Host-Keys (/etc/ssh/ssh_host_*_key.pub) und 0600 oder restriktiver für Private-Host-Keys (/etc/ssh/ssh_host_*_key).

AllowUsers / AllowGroups

Expliziter SSH-Zugriff für bestimmte Benutzer oder Gruppen, statt über die TCP-Wrapper- oder firewalld-Schicht. Mindestens eine der Direktiven AllowUsers, AllowGroups, DenyUsers oder DenyGroups sollte gesetzt sein.

Login-Banner

Banner /etc/issue.net setzen; die Datei selbst mit einem nüchternen, juristisch tragfähigen Warnhinweis befüllen (in Rechtsverfahren hat sich ein expliziter Hinweis auf Autorisierungspflicht bewährt).

MaxStartups, MaxSessions, MaxAuthTries

Oben in der Baseline bereits gesetzt. CIS schreibt MaxAuthTries <= 4, MaxStartups <= 10:30:60 vor.

Benutzerzugriff auf SSH steuern

per TCP-Wrapper

Der Zugriff auf den SSH-Daemon lässt sich mittels /etc/hosts.allow und /etc/hosts.deny steuern, den sogenannten TCP Wrappers-Dateien. Der Servicename zur Steuerung lautet hier sshd. Soll der SSH-Service nur aus der Domäne linuxfabrik.ch erreichbar sein, trägt man in der /etc/hosts.deny ein:

sshd:ALL EXCEPT .linuxfabrik.ch

Die Datei /etc/hosts.allow wird zuerst gelesen. Wird kein passender Match gefunden, kommt die /etc/hosts.deny zur Anwendung. Wird wieder kein passender Match gefunden, wird der Zugriff gewährt. Die Dateien lassen sich auch einzeln entfernen.

Weil es einfacher und sehr effektiv ist, empfehlen wir, nur die Allow-Liste zu pflegen und allen anderen in der Deny-Liste den Zugriff zu entziehen.

per /etc/sshd/sshd_config
/etc/ssh/sshd_config
AllowUsers root linus@host
AllowGroups ...
DenyUsers ...
DenyGroups ...
per /etc/passwd

Um den Benutzer linus auszuschliessen, kann man diesem auf dem SSH-Host auch den Shell-Zugriff entziehen:

usermod --shell=/bin/false linus

Tipp

Es ist allgemein empfohlen, den SSH-Zugang für root abzuschalten (PermitRootLogin no). In so einem Fall erstellt man sich einen Standard-Benutzer, packt diesen in die wheel-Gruppe, loggt sich mit diesem über SSH ein, arbeitet mit sudo oder wechselt mit su - in die root-Shell.

SFTP

Es gibt des öfteren die Anforderung, einen möglichst sicheren SFTP-Server aufzusetzen. Die SFTP-Benutzer sollen dabei ausschliesslich SSH-Keys verwenden, keine interaktive Shell per SSH öffnen und ihr SFTP-Verzeichnis auch nicht verlassen dürfen. Alle anderen SSH-Logins sollen von diesen Einschränkungen nicht betroffen sein. Aus Admin-Sicht soll das ganze möglichst auch ohne Zusatzsoftware wie VSFTP oder andere auskommen, sondern mit dem SSH-Daemon umgesetzt werden.

Geht. Zunächst sicherstellen, dass eine Authentifizierung mit Public-Keys möglich ist:

/etc/ssh/sshd_config
PubkeyAuthentication yes

Eine Benutzergruppe namens sftpusers anlegen:

groupadd sftpusers

Die einzelnen SFTP-Benutzer der Benutzergruppe sftpusers hinzufügen:

usermod --groups sftpusers linus

Die SSH Public-Keys der einzelnen SFTP-Benutzer in ihren jeweiligen Home-Verzeichnissen ablegen. Anschliessend:

chown linus:linus /home/linus/.ssh/authorized_keys
chmod 0600 /home/linus/.ssh/authorized_keys

Fehlt nur noch die Konfiguration des SSH-Daemon. Folgende Einstellungen ans Ende der /etc/ssh/sshd_config packen und danach den SSH-Server neu starten:

/etc/ssh/sshd_config
Subsystem sftp internal-sftp

Match Group sftpusers
  AllowTcpForwarding no
  ChrootDirectory /home
  ForceCommand internal-sftp
  PasswordAuthentication no
  X11Forwarding no
systemctl restart sshd

Das war es schon. Der Client kann sich jetzt verbinden:

sftp linus@host
sftp> pwd
sftp> ls
sftp> cd linus

Die wichtigsten SFTP-Kommandos…

… direkt auf dem SFTP-Server:
  • pwd: Aktuelles Verzeichnis ausgeben.

  • mkdir: Verzeichnis anlegen.

  • cd: Verzeichnis wechseln.

  • get /path/to/local/file: Lokale Datei auf den entfernten Client kopieren.

  • put /path/to/remote/file: Entfernte Datei auf den SFTP-Server kopieren.

  • exit: Verbindung beenden.

… gegen den Client:
  • lpwd: „local pwd“, aktuell genutztes Client-Verzeichnis ausgeben.

  • lmkdir: Client-Verzeichnis anlegen.

  • lcd: Client-Verzeichnis wechseln.

Die „local“-Varianten bedeuten also „Ausführung auf dem Client“. Alle anderen Kommandos werden auf dem SFTP-Server ausgefuehrt, wie bei SSH auch.

Siehe auch man sftp.

Port-Foward-only User

Manchmal benötigt man einen User-Account, der nur Port-Forwarding verwenden darf, also keinen Shell-Zugriff haben soll. Dazu muss zuerst ein UNIX User erstellt werden. Der User

useradd portfwdonly

Und danach folgende SSH-Einstellungen gesetzt werden.

/etc/ssh/sshd_config
Match User portfwdonly
    # deny all
    AllowAgentForwarding no
    AllowStreamLocalForwarding no
    ForceCommand echo 'Port forwarding only account. Shell access is not allowed. Please use the "-N" option for ssh.'
    PermitTTY no
    PermitTunnel no
    PermitUserRC no
    X11Forwarding no

    # allow explicitly
    PermitOpen 127.0.0.1:3306 localhost:3306

Zu beachten ist, dass der User sowohl Port-Forwarding als auch Reverse Port-Forwarding mit den freigegebenen Ports verwenden darf.

Performance

Mit folgendem Skript lässt sich die Geschwindigkeit einiger SSH-Chiffren im Vergleich testen (benötigt einen passwort-losen SSH-Zugang auf den eigenen Host). Die Performance ist stark abhängig von der darunterliegenden / verwendeten Hardware:

#!/usr/bin/env bash
for i in $(ssh -Q cipher); \
    do dd if=/dev/zero bs=1M count=1000 status=progress 2> /dev/null \
        | ssh -c "aes256-gcm@openssh.com" localhost "bash -c 'time -p cat' > /dev/null" 2>&1 \
        | grep real \
        | gawk '{print "'"$i"': "1000 / $2" MByte/s, " $2 " s" }' \
        && sleep 1;
done

Resultat auf einer OpenStack Cloud-VM:

aes256-gcm@openssh.com: 248.139 MByte/s, 4.03 s
aes128-gcm@openssh.com: 248.139 MByte/s, 4.03 s
aes256-ctr: 247.525 MByte/s, 4.04 s
chacha20-poly1305@openssh.com: 242.131 MByte/s, 4.13 s
aes256-cbc: 241.546 MByte/s, 4.14 s
3des-cbc: 240.385 MByte/s, 4.16 s
aes192-ctr: 234.742 MByte/s, 4.26 s
aes128-cbc: 233.645 MByte/s, 4.28 s
aes128-ctr: 230.947 MByte/s, 4.33 s
aes192-cbc: 227.273 MByte/s, 4.40 s
rijndael-cbc@lysator.liu.se: 194.553 MByte/s, 5.14 s

Resultat auf einer VM in KVM auf einem Notebook mit Intel-Prozessor und NVMe:

aes256-cbc: 1369.86 MByte/s, 0.73 s
chacha20-poly1305@openssh.com: 1265.82 MByte/s, 0.79 s
aes192-ctr: 1234.57 MByte/s, 0.81 s
3des-cbc: 1204.82 MByte/s, 0.83 s
aes192-cbc: 1176.47 MByte/s, 0.85 s
aes128-gcm@openssh.com: 1162.79 MByte/s, 0.86 s
aes128-cbc: 1149.43 MByte/s, 0.87 s
aes256-ctr: 961.538 MByte/s, 1.04 s
aes256-gcm@openssh.com: 925.926 MByte/s, 1.08 s
aes128-ctr: 925.926 MByte/s, 1.08 s

Troubleshooting

Postponed publickey for root from 10.26.6.74 port 54321 ssh2

Die RSA-Keys stimmen, ssh-copy-id verwendet bzw. Dateiberechtigungen auf alle Keys stimmen, und SELinux motzt auch nicht? Dann liegt es daran, dass man das Schlüsselpaar auf der Client-Maschine unter einem anderen Benutzer (z.B. linus) erzeugt hat als für den Benutzer, mit dem man sich auf der Zielmaschine anmelden möchte (z.B. root). Hier hilft die explizite Angabe des zu kopierenden SSH-Keys per ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.26.6.74.

Wie erhält man den SSH-Fingerprint zu einem SSH-Server?

Am einfachsten, man löscht den Eintrag in seiner ~/.ssh/known_hosts und verbindet sich neu.