Howto zum Thema SSH

Diesen Beitrag schrieb ich 14 Jahre und 11 Monate zuvor; die nachfolgenden Ausführungen müssen heute weder genau so nach wie vor funktionieren, noch meiner heutigen Meinung entsprechen. Behalte das beim Lesen (und vor allem: beim Nachmachen!) bitte stets im Hinterkopf.

Geschätzte Lesezeit: 6 Minuten

In aller Regel ist das Konfigurations-File des sshd die /etc/ssh/sshd_config; hier werden die Änderungen vorgenommen. Tiefergehende Fragen beantwortet unter anderem die Manpage (man 5 sshd_config). Fangen wir also vorne an…

Das Protokoll

Die ursprüngliche SSH-Protokoll-Version (1) wurde schon vor längerer Zeit durch Version 2 abgelöst; aus Gründen der Abwärtskompatibilität kann mittels Protocol 2,1 definiert werden, dass beide Protokolle verwendet werden können – je nachdem, was der Client anfordert. Ist dies jedoch nicht zwingend benötigt, sollte man Abstand davon nehmen – Version 1 weist mehrere bekannte Sicherheitslücken auf. Der entsprechende Parameter in der Konfiguration heißt dann

Protocol 2

root-Login verbieten

Für den User root sollte die grundsätzliche Login-Möglichkeit deaktiviert werden; sicherer und auch besser nachvollziehbar ist es, wenn einzelne angemeldete User per su bzw. sudo arbeiten. Der entsprechende Parameter in der Konfiguration lautet

PermitRootLogin no

Nur bestimmte User zulassen

In aller Regel ist die Menge der User, die sich auf einem Server per SSH anmelden müssen, recht begrenzt; erlaubt man diesen Usern explizit den Zugriff, ist er allen anderen implizit verboten, und das schließt dann beispielsweise System-User mit ein. Um den Usern fritz, martha und hugibaz den Zugriff zu gewähren, lautet der entsprechende Parameter in der Konfiguration also

AllowUsers fritz martha hugibaz

Versuchen sich nun die User mail, operator und frank an der Maschine anzumelden, so erscheint im /var/log/auth.log (systemabhängig, kann bsp. auch /var/log/secure sein) eine Ausgabe wie diese:

auth.log:May 8 01:06:28 gateway sshd[3653]: User mail from 12.34.56.78 not allowed because not listed in AllowUsers
auth.log:May 8 01:06:31 gateway sshd[3658]: User operator from 12.34.56.78 not allowed because not listed in AllowUsers
auth.log:May 8 01:06:47 gateway sshd[3691]: User frank from 12.34.56.78 not allowed because not listed in AllowUsers

Verbindungszeiten kontrollieren

Man kann davon ausgehen, dass ein User, der vor seinem Terminal sitzt und sich anmelden möchte, einigermaßen zeitnah Nutzernamen und Passwort eingeben wird; jeder SSH-Task, der gestartet wurde und nun auf Eingabe der Login-Credentials wartet, kostet Rechenzeit und Speicher – weshalb die Zahl der Prozesse möglichst nicht unnötig hoch sein sollte. Mit dem Parameter LoginGraceTime 60 gibt man dem sshd auf den Weg, dass er, sollte sich innerhalb von 60 Sekunden nichts getan haben, den gestarteten Task wieder beenden kann. Diese 60 Sekunden erscheinen auf Anhieb recht großzügig, ein geringerer Wert ist jedoch kaum anzuraten; im Falle, dass die Maschine einmal unter enormer Last stünde, würde die Kommunikation mit dem sshd verzögert und der Task beendet, noch bevor ein Login überhaupt möglich war – das kann gefährlich werden, da es ein Eingreifen bzw. Einloggen unmöglich macht.

LoginGraceTime 60

Anzahl paralleler Tasks kontrollieren

Wie wir eben gesehen haben, startet jeder Login-Versuch einen SSH-Task auf dem Server; steht der Server nun unter einer SSH-Attacke, muss er potentiell hunderte Logins innerhalb kürzester Zeit abarbeiten – und für jeden dieser Logins einen eigenen Task starten, was zu lasten der Performance der Maschine gehen wird. Diese Zahl paralleler Tasks kann jedoch kontrolliert werden, in unserer Konfiguration würde sich beispielsweise der folgende Parameter finden:

MaxStartups 3:30:10

Zur Erklärung: hier sind nun zwei unbestätigte (also noch im Login-Vorgang befindliche) SSHD-Verbindungen immer erlaubt (entspricht dem ersten Wert abzüglich 1). Ab der dritten einschließlich – was dem ersten Wert entspricht – wird jede weitere Verbindung mit einer Wahrscheinlichkeit von 30% abgelehnt (was dem zweiten Wert entspricht). Die Wahrscheinlichkeit steigt linear an, bis bei 10 offenen Verbindungen – was dem dritten Wert entspricht – jeder weitere Verbindungsversuch mit einer Wahrscheinlichkeit von 100% abgewiesen wird. Aber: bestehende SSH-Sessions mit erfolgreich eingeloggten Usern werden hier nicht eingerechnet, insofern sind die o.g. Defaults in der Regel ausreichend; bei „großen“ Maschinen mit vielen Usern müssen die Werte entsprechend angepasst werden.

Umlegen auf anderen Port

Port 22 ist der Standard-Port für sshd, und lange Zeit galt es als sicher, den Dienst auf einem anderen Port (bsp. 24) lauschen zu lassen; da die Netzwerkscanner inzwischen nicht mehr nur prüfen, ob auf einem Port ein Dienst sitzt, sondern auch welcher Dienst da lauscht, kann ich mich dieser weitverbreiteten Meinung nur bedingt anschließen; der Vollständigkeit halber sei es aber erwähnt, die Option lautet

Port 24

Listen Address

Es ist möglich (und in einigen Fällen sogar ratsam), den IP-Adressbereich einschränken, so dass sshd nur auf einen klar definierten internen Netzbereich lauscht; ein denkbarer Einsatzbereich wäre hier unter anderem, SSH-Zugriffe ausschließlich aus einem OpenVPN-Netz zu gestatten.

ListenAddress 172.16.4.1

X11Forwarding

Per Default ist diese Option auf „no“ gesetzt, d.h. X11Forwarding über SSH wird nicht zugelassen; möchte man dieses erlauben, muss der Parameter explizit auf „yes“ gesetzt werden:

X11Forwarding yes

PermitTunnel

SSH-Tunnel können nur dann aufgebaut und benutzt werden, wenn dies explizit erlaubt wird (per Default wird es nicht erlaubt); mögliche Werte sind „yes“, „no“, „point-to-“ und „ethernet“.

PermitTunnel yes

Ein sicheres Passwort für jeden User

Natürlich ist die Absicherung des Servers hinfällig, wenn dem Angreifer Usernamen bekannt sind und die dazugehörigen Passwörter schlicht erraten werden können; ein mögliches Tool zum Erstellen der Passwörter ist pwgen, das auf allen gängigen Distributionen einfach als Paket nachinstalliert werden kann.

$ pwgen -B -C -n 12 1
caiph7eChaex

So generiert der Aufruf uns ein (kenntlich gemacht durch die 1 am Ende) 12-stelliges Passwort (kenntlich gemacht durch die 12), das mindestens eine Ziffer enthält (-n), mindestens einen Großbuchstaben (-c) und ansonsten keine zweideutigen Zeichen (wie „Null vs. groß O“ oder „Ziffer eins vs. klein L“). Dieses Passwort ist so sicher, dass es sich kein Schwein merken wird :D

Sicherheit gewinnen durch Key-Auth

Der Zugriff auf die Maschine kann so weit eingeschränkt werden, dass das Login ausschließlich über den SSH-Key erfolgt und nicht mehr, wie zuvor, über die Eingabe des Passworts; das verringert die Wahrscheinlichkeit einer erfolgreichen Attacke, da der Angreifer die entsprechenden Schlüssel in seine Gewalt bringen müsste, und es hat einen weiteren Vorteil: der User muss sich das 12-stellige pwgen-Passwort nicht merken (und auch nicht auf einem Post-It an den Monitor kleben), da er es zum Login nicht benötigt (es sei denn, er möchte oder muss mit sudo arbeiten).

PermitEmptyPasswords no
PasswordAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes

Gehen wir nun also von User harald aus; harald ist ein neuer User und möchte Zugriff auf die Maschine gateway haben, gateway jedoch akzeptiert nur Logins mit hinterlegten Keys. Als erstes muss der User sich also einen SSH-Key generieren, sofern er noch keinen besitzt:

$ ssh-keygen -t rsa

Dies erzeugt im $HOME des Users den Ordner .ssh/, in welchem unter anderem diese beiden Dateien zu finden sind:

-rw------- 1 harald users 887 Apr 16 16:48  id_rsa     # das ist der private Schlüssel, der unter allen Umständen beim User verbleiben muss
-rw------- 1 harald users 222 Apr 16 16:48  id_rsa.pub # das ist der öffentliche Schlüssel (Public Key)

WICHTIG: beide Dateien müssen dem User harald gehören und dürfen nur durch ihn gelesen und beschrieben werden (chmod 0600)!

Um nun auf den Host gateway zugreifen zu können, müssen die folgenden Schritte vorgenommen werden:

  • Nur weil harald auf seinem Rechner mit der Login-ID harald arbeitet, muss er das auf dem Host gateway nicht zwingend auch tun; im Vorfeld ist also zu klären, unter welcher Nutzerkennung er wird arbeiten müssen.
  • Inzwischen ist bekannt, dass harald auf dem entfernten Host gateway den Mailserver verwalten soll – deshalb soll er unter der eigens hierfür eingerichteten Kennung mailadmin arbeiten.
  • So wird harald nun dem zuständigen Admin den Inhalt seines Public Keys – also der Datei id_rsa.pub – zur Verfügung stellen.
  • Der Admin wird diesen Key an die Datei /home/mailadmin/.ssh/authorized_keys anhängen bzw. dieses File erstellen, sollte es noch nicht existieren (auch das authorized_keys-File muss chmod 0600 sein!).

Nun kann der User harald sich von genau diesem Host, auf dem sein SSH-Key verfügbar ist, auf dem Host gateway einloggen:

$ ssh mailadmin@gateway

forced-commands-only

Beispiel: in unserem Setup ist nicht gewünscht, dass root sich über SSH einloggen kann; wir möchten aber einen SSH-Tunnel aufbauen zwischen einer lokalen und einer entfernten Maschine, und dieses Tunnel-Setup möchten wir durch Scripte automatisieren. Das Problem: nur root darf per ifconfig die Konfiguration der Interfaces ändern. Deshalb setzen wir in der sshd_config statt, wie vorher einfach „no“, den entsprechenden Parameter auf yes:

PermitRootLogin forced-commands-only

Auf diesem Rechner wird für root dann eine autorized_keys hinterlegt, die dem folgenden Schema folgt:

command="$KOMMANDO_NEBST_PARAMETERN" $KEY

Soll User root also das Login grundsätzlich verwehrt bleiben, das Setzen der Tunnel-Parameter aber erlaubt sein, so könnte das in etwa so aussehen:

command="/sbin/ifconfig tun0 192.168.6.2 dstaddr 192.168.6.1 up" ssh-rsa [...]

SSH-Keys mit Passphrase

Jeder hat nun prinzipell Zugang als User mailadmin auf gateway – sofern er, auf welchem Wege auch immer, Zugriff auf haralds Maschine hat und über den hinterlegten harald-Key. Natürlich kann das ein Sicherheitsloch darstellen; deshalb gibt es die Möglichkeit, beim Anlegen eines neuen SSH-Keys diesem eine Passphrase mit auf den Weg zu geben. Im vorliegenden Falle würde dann nicht mehr das (12-stellige computergenerierte) Host-Passwort abgefragt werden, sondern lediglich die Passphrase des SSH-Keys. Die kann der User sich selbst aussuchen, und mit etwas Glück gelingt ihm dabei die Grätsche zwischen „merkbar“ und „einigermaßen sicher“.

Einschränkungen durch TCP-Wrapper

Ist sshd mit Unterstützung für TCP-Wrapper kompiliert, können auch die Dateien

  • /etc/hosts.allow und
  • /etc/hosts.deny

zum Einsatz kommen; prüfen lässt sich dies mit einem Aufruf wie diesem:

# ldd /usr/sbin/sshd | grep wrap
  libwrap.so.0 => /lib/libwrap.so.0 (0xb7f71000)

Möchte man nun einem konkreten Host mit IP 192.168.1.2 den Zugriff verbieten (User-unabhängig!), kann beispielsweise in der Datei /etc/hosts.deny dieser Eintrag hinterlegt werden:

sshd: 192.168.1.2

Nach Abspeichern der Datei – ein Reload des sshd ist nicht nötig – werden Login-Versuche von diesem Host abgewehrt; der User erhält als Fehlermeldung

ssh_exchange_identification: Connection closed by remote host

Währenddessen wird im Logfile (/var/log/auth.log oder /var/log/secure) eine Meldung wie diese vermerkt:

May 18 14:38:10 gateway sshd[12455]: refused connect from 192.168.1.2 (192.168.1.2)

An dieser Stelle gibt es vielfältige Möglichkeiten, so kann beispielsweise der Admin bzgl. jeden Anmeldeversuchs benachrichtigt werden usw. … Sinnvollerweise sollte man sich die Manpages (vman 5 hosts_access`) zu Gemüte führen, um die Möglichkeiten der TCP-Wrapper voll auszuschöpfen.

Troubleshooting

Bei Problemen sind die Logfiles zu konsultieren, bei Connect-Problemen kann der „verbose“ Aufruf (vssh -vvv`) sehr hilfreich sein.

Alle Bilder dieser Seite: © Marianne Spiller – Alle Rechte vorbehalten
Hintergrundbild: Bild genauer anschauen – © Marianne Spiller – Alle Rechte vorbehalten

Eure Gedanken zu „Howto zum Thema SSH“

Ich freue mich über jeden Kommentar, es sei denn, er ist blöd. Deshalb behalte ich mir auch vor, die richtig blöden kurzerhand wieder zu löschen. Die Kommentarfunktion ist über GitHub realisiert, weshalb ihr euch zunächst dort einloggen und „utterances“ bestätigen müsst. Die Kommentare selbst werden im Issue-Tracker und mit dem Label „✨💬✨ comment“ erfasst – jeder Blogartikel ist ein eigenes Issue. Über GitHub könnt ihr eure Kommentare somit jederzeit bearbeiten oder löschen.