Einführung

Verbindet man sich zum ersten Mal per SSH mit einem Server, sieht man den Fingerabdruck des Servers. Diesen sollte man im Idealfall vergleichen und erst mit yes bestätigen, wenn man sich sicher ist, dass es sich um den richtigen Fingerprint handelt. Stimmt der Fingerabdruck nicht, könnte man Opfer einer Man in the Middle Attacke sein. Das Vergleichen der Fingerprints ist etwas mühsam und mittels fuzzying (beispielsweise mit dem Tool ffp) können sehr ähnliche Fingerprints erstellt werden, welche dem Menschen auf den ersten Blick gleich erscheinen. Man kann sich einfach vor gefälschten SSH Fingerprints schützen, indem man diese in einem DNSSEC signierten speziellen DNS Record hinterlegt. Hierfür gibt es den speziellen SSHFP Record.

Wofür brauche ich den SSHFP Record?

Verbindet man sich zum ersten Mal per SSH mit einem Server, sieht man den Fingerabdruck des Servers. Diesen kann man mit yes bestätigen und damit in die Datei ~/.ssh/known_hosts eintragen. Hat sich der Fingerabdruck bei einem erneuten Verbinden verändert, bekommt man eine Warnung. Ist es der selbe, ist alles OK und der Verbindungsaufbau geht weiter.

Damit der Finerprint nicht von Hand verglichen werden muss, kann man diesen in einem speziellen DNS Record hinterlegen. Dieser DNS Record heisst SSHFP und wurde im RFC 4155 spezifiziert und im RFC 6594 erweitert.

Automatisches erstellen des SSHFP Records

Den SSHFP Record kann man sich direkt mit ssh-keygen generieren lassen. Hier ein Beispiel für den Host motd.ch:

$ ssh-keygen -r motd.ch.
motd.ch. IN SSHFP 1 1 598e08adbfdee83121bb4e646fa4873574243a81
motd.ch. IN SSHFP 2 1 69174e7205988757021b546b70342200f8465606

Wichtig:

  • Dies muss auf dem Host ausgeführt werden, wessen SSHFP Record man erstellen will.
  • Man beachte den Punkt am Schluss des Hostsnamens. Dieser ist nötig, damit der Eintrag in der Zone stimmt. Ohne “Root Punkt” würde ein Eintrag für motd.ch.motd.ch. erstellt werden, da der Nameserver gegebenenfalls den Zonennamen bzw. $ORIGIN an den Hostnamen anhängt.

Aufbau des SSHFP Records

Die erste Zahl steht für den verwendeten Algorithmus:

  • 0: Reserviert
  • 1: RSA
  • 2: DSS
  • 3: ECDSA
  • 4: ED25519

Die zweite Zahl steht für den Fingerprint Typ:

  • 0: Reserviert
  • 1: SHA-1
  • 2: SHA-256

Diese Aufstellung ist auch bei der IANA abrufbar: DNS SSHFP Resource Record Parameters: https://www.iana.org/assignments/dns-sshfp-rr-parameters/dns-sshfp-rr-parameters.xhtml.

Händisches Erstellen des SSHFP Records

Ältere Versionen von ssh-keygen generieren keine Einträge für den ECDSA und den ED25519 Algorithmus. Diese muss man gegebenenfalls von Hand erstellen. Ich habe mir folgendes Script geschrieben, welches für alle verfügbaren Algorithmen und Fingerprint Typen alle SSHFP Records erstellt:

#!/usr/bin/env bash

HOST="$1"

if (($# < 1)) then echo "Usage: sshfpgen "
exit 1
fi

for i in /etc/ssh/ssh_host_*_key.pub
do
case "`cut -d_ -f3 <<< $i`"
  in
    rsa)
      echo $HOST IN SSHFP 1 1 `cut -f2 -d ' '  $i | base64 -d | sha1sum  | cut -f 1 -d ' '`
      echo $HOST IN SSHFP 1 2 `cut -f2 -d ' '  $i | base64 -d | sha256sum  | cut -f 1 -d ' '`
    ;;
    dsa)
      echo $HOST IN SSHFP 2 1 `cut -f2 -d ' '  $i | base64 -d | sha1sum  | cut -f 1 -d ' '`
      echo $HOST IN SSHFP 2 2 `cut -f2 -d ' '  $i | base64 -d | sha256sum  | cut -f 1 -d ' '`
    ;;
    ecdsa)
      echo $HOST IN SSHFP 3 1 `cut -f2 -d ' '  $i | base64 -d | sha1sum  | cut -f 1 -d ' '`
      echo $HOST IN SSHFP 3 2 `cut -f2 -d ' '  $i | base64 -d | sha256sum  | cut -f 1 -d ' '`
    ;;
    ed25519)
      echo $HOST IN SSHFP 4 1 `cut -f2 -d ' '  $i | base64 -d | sha1sum  | cut -f 1 -d ' '`
      echo $HOST IN SSHFP 4 2 `cut -f2 -d ' '  $i | base64 -d | sha256sum  | cut -f 1 -d ' '`
    ;;
  esac
done

Die aktuellste Version davon gibt es auf GitHub in meinem Scripts Repository: sshfpgen.

So generiert man alle SSHFP Records:

$ ./sshfpgen motd.ch.
motd.ch. IN SSHFP 2 1 69174e7205988757021b546b70342200f8465606
motd.ch. IN SSHFP 2 2 d6b6aba95e89b9b117480dfb495d961cfbadac3ef8dc6fd4d8d82a3b7ee0f5e2
motd.ch. IN SSHFP 3 1 63ebb25f257e0e91fb689132b4f69afa529ddd85
motd.ch. IN SSHFP 3 2 c2cdc18577ac20773f8c8015452ff18bb54bd7da17ab66c5f5e1a266336de232
motd.ch. IN SSHFP 1 1 598e08adbfdee83121bb4e646fa4873574243a81
motd.ch. IN SSHFP 1 2 cbf16ba44d531224d8af0ca49440e05826a2d7e2aa68e179136cb42c33e5d160

Wie man sieht sind jetzt einige Einträge (Neu ECDSA und zusätzlich alle mit SHA256) mehr erstellt worden. Diese kann man jetzt ins Zonenfile eintragen.

Eintragen ins Zonenfile

Dieser SSHFP Record trägt man jetzt in der DNS Zone ein, welche für diesen Hostnamen zuständig ist. Damit man der Antwort vom DNS Server auch trauen kann, sollte diese Zone auch mit DNSSEC signiert sein und der verwendete Resolver sollte die Antwort überprüfen (man beachte das ad Flag in der Ausgabe).

$ dig motd.ch sshfp  +nostats +noadditional +noauthority +noquestion @8.8.8.8 ` `
; <<>> DiG 9.9.2-P2 <<>> motd.ch sshfp +nostats +noadditional +noauthority +noquestion @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7916
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; ANSWER SECTION:
motd.ch.		86400	IN	SSHFP	3 2 C2CDC18577AC20773F8C8015452FF18BB54BD7DA17AB66C5F5E1A266 336DE232
motd.ch.		86400	IN	SSHFP	1 1 598E08ADBFDEE83121BB4E646FA4873574243A81
motd.ch.		86400	IN	SSHFP	1 2 CBF16BA44D531224D8AF0CA49440E05826A2D7E2AA68E179136CB42C 33E5D160
motd.ch.		86400	IN	SSHFP	2 1 69174E7205988757021B546B70342200F8465606
motd.ch.		86400	IN	SSHFP	2 2 D6B6ABA95E89B9B117480DFB495D961CFBADAC3EF8DC6FD4D8D82A3B 7EE0F5E2
motd.ch.		86400	IN	SSHFP	3 1 63EBB25F257E0E91FB689132B4F69AFA529DDD85

SSH Client konfigurieren

Jetzt muss man dem SSH Client noch sagen, dass er die SSHFP Records zur Verifizierung verwenden soll. Dazu fügt man in der Datei /etc/ssh/ssh_config folgenden Eintrag ein:

VerifyHostKeyDNS ask

Durch die Option ask muss man weiterhin mit yes bestätigen, man bekommt jedoch den Hinweis, dass der Key mit dem SSHFP Record übereinstimmt.. Verwendet man yes statt ask wird der Key automatisch akzeptiert.

SSH Verbindung aufbauen

Folgendermassen sieht der Verbindungsaufbau aus, wenn man sich zum ersten Mal mit dem Server verbindet:

$ ssh motd.ch
The authenticity of host 'motd.ch (5.45.105.71)' can't be established.
ECDSA key fingerprint is 8e:ff:01:35:98:88:56:f7:1f:7a:11:28:86:e4:34:11.
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'motd.ch,5.45.105.71' (ECDSA) to the list of known hosts.

Yay! Man sieht die Zeile: “Matching host key fingerprint found in DNS.”. Der Public SSH Fingerprint stimmt also mit dem SSHFP Record überein.

Stimmt der SSHFP Record und der Fingerprint nicht überein, erscheint folgende Meldung:

$ ssh motd.ch
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
8e:ff:01:35:98:88:56:f7:1f:7a:11:28:86:e4:34:11.
Please contact your system administrator.
Update the SSHFP RR in DNS with the new host key to get rid of this message.
The authenticity of host 'motd.ch (5.45.105.71)' can't be established.
ECDSA key fingerprint is 8e:ff:01:35:98:88:56:f7:1f:7a:11:28:86:e4:34:11.
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?