SSH Absichern: Authentifizierung mit public Key

Die Secure Shell (SSH) ist der Nachfolger von Telnet und wurde ursprünglich entwickelt, mehr Sicherheit gegenüber Telnet zu bieten. Dieses Ziel wurde auch erreicht, denn SSH verschlüsselt die Verbindung komplett.

Das schwächste Glied in der Kette bleibt nun der Login-Screen: Jeder, der einen Benutzernamen samt Passwort für das System kennt, kann sich einloggen. Problematisch wird es, wenn schwache Passwörter verwendet werden, die durch BruteForce-Attacken erraten werden können. Daher empfiehlt es sich, den SSH-Zugang zusätzlich abzusichern:

Anmeldung mit privatem und öffentlichem Schlüssel

Im Gegensatz zu herkömmlichen Passwörtern sind die hier genutzten privaten/öffentlichen Schlüssel um einiges sicherer. Um den Zugang über SSH abzusichern, muss jeder Client, der Zugriff auf ein Konto des Servers haben soll, zunächst ein Schlüsselpaar erzeugen. Wichtig ist, dass der private Schlüssel mit einer Passphrase versehen wird! Das kann bei folgenden Befehlen auch erst beim Aufruf des OpenSSL-Tools geschehen, da der Schlüssel für diesen Schritt eh unverschlüsselt vorliegen muss:

#SSH-Schlüsselpaar generieren, ohne passphrase
ssh-keygen -f id_rsa
cd ~/.ssh

#Privaten Schlüssel mit PKCS8/PBKDF2 schützen
openssl pkcs8 -topk8 -in id_rsa -out id_rsa.pkcs8
rm id_rsa
mv id_rsa.pkcs8 id_rsa

#Dateirechte anpassen
chmod 600 ~/.ssh/id_rsa

Als praktischen Ein-Zeiler zum Kopieren:

ssh-keygen -f id_rsa && cd ~/.ssh && openssl pkcs8 -topk8 -in id_rsa -out id_rsa.pkcs8 && rm id_rsa && mv id_rsa.pkcs8 id_rsa && chmod 600 ~/.ssh/id_rsa

Für jedes Konto auf dem Server existiert eine authorized_keys Datei, im Verzeichnis .ssh des Home-Ordners. Wird der öffentliche Schlüssel eines Clients in dieser Datei hinterlegt, hat er per SSH Zugriff auf das entsprechende Konto. Das sicherste wäre es natürlich, den Schlüssel lokal per USB-Stick zu kopieren. Andernfalls kann man das Programm ssh-copy-id verwenden:

ssh-copy-id damon@nomadnetbook

Alternativ kann man auch den Inhalt der ~/.ssh/id_rsa.pub des Clients mit einem Texteditor kopieren und über SSH in ~/.ssh/authorized_keys auf dem Server einfügen.

Wurde der öffentliche Schlüssel des Clients in der authorized_keys Datei des Server-Kontos eingetragen, wird die Passwortauthentifizierung von SSH deaktiviert. Dazu wird die Datei /etc/ssh/sshd_config auf dem Server editiert. Folgende Parameter müssen geändert werden:

PasswordAuthentication no
UsePAM no

Fertig! Nach einem Neustart oder Reload (sudo /etc/init.d/ssh reload) des SSH-Servers werden nur noch Clients, deren Schlüssel in einer authorized_keys Datei vorliegt, auf dem System akzeptiert.

Technische Details

In der Regel wird ein 2048-bit RSA Schlüsselpaar verwendet. Zur Authentifizierung sendet der Client einen Hash, der durch den privaten Schlüssel verschlüsselt wurde. Der Server nutzt den öffentlichen Schlüssel des Clients um den übermittelten Hash zu entschlüsseln.

Der entschlüsselte Hash wird mit dem vom Server erstellten Hash abgeglichen. Der Hash wurde aus mehreren Informationen der Session erstellt und ist beiden Seiten bekannt. Sind die Hashes also gleich, weiß der Server dass

  1. Die Verbindungsparameter übereinstimmen, und
  2. Der übertragene Hash korrekt mit dem privaten Schlüssel des Clients verschlüsselt wurde

Somit wird dem Client vertraut, und er ist authentifiziert. So weit so gut, nun ist die Verbindung verschlüsselt, die Authentifizierung findet durch asymmetrische Kryptografie statt. Das schwächste Glied der Kette ist nun, je nach Ansicht, entweder der Zugriff auf den privaten Schlüssel des Clients oder die authorized_keys Datei auf dem Server. Daher sollte sichergestellt werden, dass nur berechtigte Personen zugriff auf diese haben.

Bein privaten Schlüssel wird dies durch eine Passphrase sichergestellt. Ergo muss diese sehr stark sein, damit der private Schlüssel sicher ist. Kommt es zum (mehr oder weniger unwahrscheinlichen) Fall, dass jemand in Besitz des privaten Schlüssels gelangt, muss sich der Besitzer auf die Stärke der Passphrase verlassen, denn der Angreifer kann nun versuchen, die Passphrase zu erraten.

Daher sollten die üblichen Regeln für gute Passwörter verwendet werden: Viele Zeichen, Sonderzeichen, Zahlen, Groß- sowie Kleinbuchstaben, möglichst zufällig. Damit soll sichergestellt werden, dass die Passphrase in keinem Dictionary auftaucht.

Der Angreifer hat aber immer noch die Möglichkeit, alle möglichen Kombinationen aus Zeichen auszuprobieren (Brute-Forcing).

Privaten Schlüssel schützen: PBKDF2

Das Problem mit herkömmlichen Passphrasen ist, dass sie schnell sind. Der verschlüsselte private Schlüssel wird in Sekundenbruchteilen durch die Passphrase symmetrisch entschlüsselt. Was dem Client einige (nicht wahrnehmbare) hundertstel Sekunden erspart, erspart einem Angreifer Stunden, Tage oder gar Jahre. Unser Ziel ist es also, das Entschlüsseln des privaten Schlüssels so zu verlangsamen, dass eine Brute-Force Attacke nicht mehr rentabel ist.

Konzepte dafür sind etwa von bcrypt bekannt. Die Hash-Funktion durchläuft den Algorithmus sehr oft, um Zeit zu schinden und Angreifern das Leben schwer zu machen. Das selbe geschieht beim Anwenden von PBKDF2 (Password Based Key Derivation Function 2).

Ich will nicht lange auf PBKDF2 und die Kompabilität eingehen, vor allem da Martin Kleppmann dies schon getan hat. Das existierende Schlüsselpaar wird, wie oben angegeben, mit

openssl pkcs8 -topks8 -in foo -out bar

mittels PKCS8 gesichert.

Probleme mit ssh-agent

Der SSH-Agent ist dazu da, den privaten Schlüssel zwischenzuspeichern: Der SSH-Client fordert den privaten Schlüssel an, um etwas mit ihm zu signieren. Der SSH-Agent entschlüsselt den privaten Schlüssel (falls, wie hier, mit einer Passphrase geschützt) und übergibt ihn an den Client. Dabei kann man auch einen Timeout setzen, sodass die Passphrase innerhalb einer bestimmten Zeitspanne nicht erneut eingegeben werden muss, um auf den privaten Schlüssel zuzugreifen.

Ist der Schlüssel durch PKCS8/PBKDF2 geschützt, hat der SSH-Agent meiner Erfahrung nach einige Probleme. Eventuell erscheint folgende Fehlermeldung:

Agent admitted failure to sign using the key.
Permission denied (publickey).

Die Lösung für das Problem ist, den SSH-Agent nicht zu nutzen. Dies kann entweder pro Session getan werden, indem dem SSH-Kommando SSH_AUTH_SOCK=0 voran gestellt wird, etwa

SSH_AUTH_SOCK=0 ssh damon@nomadnetbook

Oder der SSH-Agent wird gar nicht erst geladen. Dazu wird die Datei /etc/X11/Xsession.options bearbeitet, die Zeile use-ssh-agent wird mit einem ‚#‘ kommentiert.

Meiner Meinung nach ist es sicherheitstechnisch eh nicht sinnvoll, den privaten Schlüssel durch den Agenten unnötig lange unverschlüsselt bereitzustellen. Schließlich ist die Passphrase buchstäblich „der Schlüssel“ zur Sicherheit dieser Authentifizierungsmethode. Ist der SSH-Agent deaktiviert, wird die Passphrase zum Entschlüsseln bei jeder Verbindung erneut eingegeben.

Variationen von Public-Key Authentifizierung

Neben den 2048 Bit RSA-Schlüsseln kann man auch einen PGP-Schlüssel zur Authentifizierung verwenden. Dadurch können Unterschlüssel genutzt, und das Vertrauen kann besser verwaltet werden. Für die Methode sind aber einige Vorbereitungen und Einstellungen nötig, der einfache Gebrauch des SSH-Keygens hingegen ist „Massentauglich“, also für fast jeden einfach nachvollziehbar.

Ein zusätzlicher Artikel zur Authentifizierung mit PGP-Schlüsseln ist in Planung, ebenso wie Email-Verschlüsselung.

Bei Fragen und Ideen nutzt wie immer die Kommentare, und falls euch der Artikel gefallen oder geholfen hat, würde ich mich freuen, wenn ihr ihn weiterleitet.

MfG
Damon Dransfeld

Dieser Eintrag wurde veröffentlicht in Linux
Bookmarken: Permanent-Link Schreibe einen Kommentar oder hinterlasse einen Trackback: Trackback-URL.
Achtung: Wordpress interpretiert bestimmte Zeichenfolgen als Markup und verändert diese. Nutzt für Programmcode lieber Gist oder PasteBin-Services und verlinkt die Code-Schnipsel.

Post a Comment

Ihre E-Mail wird niemals veröffentlicht oder verteilt. Benötigte Felder sind mit * markiert

*
*

Du kannst diese HTML Tags und Attribute verwenden: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>