HTTP Public Key Pinning (HPKP) mit Apache/Ubuntu Webserver

Die verschlüsselte Übertragung von Webseiten via HTTPS funktioniert sicher und zuverlässig. Weniger sicher und zuverlässig ist jedoch die verwendete Technik zur Identifizierung des Gegenübers. Derzeit sollen Certificate Authorities (CAs) sicherstellen dass man beim Aufruf von z.B. https://www.techgrube.de auch wirklich direkt mit techgrube.de spricht und nicht etwa mit einer Phisingsite. Das Problem ist dass die gängigen Browser hunderten von CAs vertrauen. Wenn ich als Webseitenbetreiber mir ein Zertifikat von „TrustedCA Number 1“ erstellen lassen hindert das einen Angreifer nicht daran sich ein gültiges Zertifikat von „TrustedCA Number2“ erstellen zu lassen. Der Besucher merkt nicht dass er auf eine falsche Seite umgeleitet wurde.

Die Gefahr dass eine HTTPS Verbindung aufgebrochen und vom Besucher unbemerkt neu verschlüsselt wird ist dabei keineswegs nur eine theoretische. So hat die auf Lenovo vorinstallierte Adware Superfish genau das gemacht. Auch in Unternehmen ist dies aus „Sicherheitsgründen“ nicht unüblich.

HTTP Public Key Pinning (kurz: HPKP) kann diese Problematik deutlich entschärfen.

Der Schlüssel ist in der ganzen Vertrauenskette das einzige Glied über das ausschließlich der Webseitenbetreiber die Kontrolle hat. Mit HPKP wird deshalb dem Browser mitgeteilt nur einem bestimmten Public Key zu vertrauen. Falls der Schlüssel kompromitiert wird wird ein Backupkey hinterlegt. Dieses Verfahren hat den Vorteil, dass das Zertifikat jederzeit neu ausgestellt werden kann, auch von einer anderen CA, ohne dass die Vertrauenskette unterbrochen wird. Voraussetzung ist nur dass sich der Schlüssel nicht ändert.

Leider lässt die Browserunterstützung für HPKP noch etwas zu wünschen übrig. Derzeit wird diese Technologie nur von Chrome und Firefox unterstützt. Da Public Key Pinning mittlerweile ein Internetstandard geworden ist kann man hoffen dass bald auch andere Browser HPKP unterstützen. Allerdings schadet die Serverseitige Unterstützung von HPKP nie. Drowser die Key Pinning nicht unterstützen ignorieren den Header einfach.

Hashes berechnen

Damit HPKP funktioniert muss die Webseite bereits für HTTPS konfiguriert sein. Außerdem müssen zwei Public Keys vorliegen. Der normale, welcher für die Verschlüsselung der Webseite genutzt wird und ein Backupkey, welcher sinnvollweise nicht auf dem Webserver gelagert wird. Gepinnt werden nicht die Keys selber, sondern deren Hashes.

Zum berechnen der Pins wird der base64 codierte SHA256 Hash des Public Keys benötigt. Diesen erhält man mit folgendem Befehl:

openssl rsa -pubout -in /PFAD/ZUM/SCHLÜSSEL.KEY -outform der | openssl dgst -sha256 -binary | base64

Die Ausgabe ist etwas wie qoH58RZSJdG7ZIGHyBkAczEAhVKVD07nyW3dT7xFiOk=

Das Ganze wird mit dem Backupkey wiederholt

Report URL

Wenn nun die Seite mit einem falschen Key aufgerufen wird schlägt der Brrowser beim Besucher Alarm. HPKP bietet jedoch auch die Möglichkeit bei einem solchen Alarm auch den Admin mittels Aufruf einer bestimmten URL zu benachrichtigen. Ein Dienst welcher sich auf das aufzeichnen und übermitteln solcher Reports spezialisiert hat ist Report URI. Der einfachste Weg um Benachrichtigungen zu erhalten ist es sich hier einen Account zu machen. Wird die wird beim Aufruf der Seite ein falscher Hashwert für den Key ausgeliefert erhält man bei Report-Uri einen Report wie im Bild zu sehen

report-uri

Apache konfigurieren

Um Public Key Pinning zu aktivieren muss man in seine VirtualHost Config des Apachen folgendes eintragen:

Header set Public-Key-Pins "pin-sha256=\'Y2urzdz7js279u9efffglwj4xdxrz0v5=\'; pin-sha256=\'K9d95ywvlwwrexxdjkvenazrsx1nwb10=\'; report-uri='https://report-uri.io/report/vbhnxkl26gdvfupwzt2j23b6b7xdn3'; max-age=5184000; includeSubdomains;"

Der erste Pin ist der Hash für den regulären Key.
Der zweite Pin ist für den Backupkey.
report-uri ist die URL die aufgerufen wird wenn die Überprüfung die Gültigkeitsprüfung fehlschlägt.
max-age gibt die Zeit in Sekunden an (hier 60 Tage), für die der Browser die Pins in seine Whitelist einträgt. Wenn innerhalb dieser Zeit die Seite mit einem Schlüssel ausgeliefert wird welcher nicht zu den Pins passt schlägt die Gültigkeitsprüfung fehl und der Seitenaufbau wird verweigert.
includeSubdomains gibt an dass die Überprüfung auch für alle Subdomains stattfindet.

Die Fett gedruckten Einträge können bzw. müssen angepasst werden

Nun muss nur noch der Apache neu gestartet werden. Ob das Pinning funktioniert kann bei SSLLabs getestet werden. Hier findet sich nun der Eintrag Public Key Pinning (HPKP) : YES

Fazit

Wenn alles gut läuft erhöht Public-Key-Pinning die Sicherheit einer SSL Verbindung deutlich. Das Problem mit den Zertifizierungsstellen, denen Vertraut werden muss wird damit aber auch nicht endgültig gelöst.

Ich habe die Nutzung von Puplic-Key-Pinning als derzeit noch sehr frickelig und seltsam erlebt. So richtig gut hat alles eigentlich nur mit der Developer Version von Google Chrome (derzeit Version 47) funktioniert. Bei Firefox hat das Reporting überhaupt nicht funktioniert. Außerdem habe ich die Erfahrung gemacht dass das Pinning oft einfach ignoriert wurde wenn bereits beim ersten Aufruf der Seite der Hash im Header und der tatsächlich ausgelieferte nicht übereingestimmt haben. Dies ist ein generelles Problem dieser Technologie, da die erste Verbindung vertrauenswürdig sein muss. Woher soll der Browser sonst auch wissen ob er dem Hash im Header, oder dem Hash des tatsächlich übertragenen Schlüssel vertrauen soll.

Da sich die Browser jedoch schnell weiterentwickeln denke ich dass HPKP bald mit allen Browsern zuverlässig und vor allem einheitlich funktioniert. Ich werde das Ganze in ein paar Monaten nochmals testen und dann unterstützen, wenn klar ist wie die einzelnen Browser auf unterschiedliche Konfigurationen reagieren. Wer derzeit diese Technologie unterstützen möchte muss IMHO viel testen. Wenn alles mitspielt und der Hash im Header (bzw. der im Browser zwischengespeicherte) und der Hash des tatsächlichen Keys nicht übereinstimmen endet der Seitenaufruf mit einer solchen Fehlermeldung

Key-pinning

 



88x31_CC_by
Dieser Artikel ist lizensiert unter einer Creative Commons Namensnennung 4.0 International Lizenz.
Titelbild „Enigma“ von Pixabay steht unter Creative Commons CC0

6 Kommentare

  • Toni

    Du vermischt hier zwei Dinge munter die getrennt betrachtet und konfiguriert werden müssen. HSTS (Http Strict Transport Security) und HPKP (Http Public Key Pinning). Die Chromium Liste ist nicht für HPKP gedacht sondern HSTS. Über diese Liste wird dann angegeben das deine Seite nur per Https angesprochen wird. Daher ist die preload Anweisung auch falsch. Die gehört zu HSTS. Was du hier nicht konfiguriert hast.

    HPKP gibt an wie der Hash des Keys aussieht. Das ist dazu gedacht Man-in-the-Middle-Angriffe abzuwehren. Dabei muss dein Browser einmal mit deiner Seite eine Verbindung aufgenommen haben um den Hash zu kennen.

    Du solltest darauf eingehen warum du 2 Pins verwendet. Das liegt daran das der zweite Pin dein Backup-Key ist. Chrome bsp. wertet das ganze nur dann richtig aus wenn 2 Hashes angegeben sind. Wenn dir nämlich dein Key abhanden kommt und du keinen zweiten definiert hast und mit diesem neuen Key ein neues Zertifikat signierst kommt niemand mehr auf deine Seite weil dein Hash sich geändert hat. Für den Browser sieht das dann wie ein MitM-Angruff aus.

    Bitte ändere den Artikel soweit ab das du erklärst wie diese beiden Mechanismen richtig konfiguriert werden. So ist er leider Falsch und gerade was diese Thema anbelangt richtet ein falscher Artikel mehr Schaden an als 10 richtige.

    • optimox

      Danke Dir für die Mühe einen so ausführlichen Kommentar zu schreiben.
      Dass es sich beim zweiten Pin um den Backupkey handelt ist im Artikel angegeben. Ich halte diesen Punkt für ausreichend beleuchtet.
      Was die Liste angeht hast Du eindeutig Recht, die Chromium Liste hat mit Key Pinning nichts zu tun. Die preload Anweisung hat an diesem Punkt auch nichts zu suchen. Umso erstaunlicher dass sich der Apache daran nicht stört. Ich werde den Artikel in diesem Punkt abändern, bzw. den Teil der nichts mit HPKP zu tun hat entfernen.
      In der Tat können Falschinformationen in solchen Beträgen sehr schädlich sein.

  • Toni

    Du vermischt hier zwei Dinge munter die getrennt betrachtet und konfiguriert werden müssen. HSTS (HTTP Strict Transport Security) und HPKP (HTTP Public Key Pinning).

    Die Chromium Liste ist nicht für HPKP gedacht sondern HSTS. Über diese Liste wird dann angegeben das deine Seite nur per HTTPS angesprochen wird. Daher ist die preload Anweisung auch falsch. Die gehört zu HSTS. Was du hier nicht konfiguriert hast.

    HPKP gibt an wie der Hash des Keys aussieht. Das ist dazu gedacht Man-in-the-Middle-Angriffe abzuwehren. Dabei muss dein Browser einmal mit deiner Seite eine Verbindung aufgenommen haben um den Hash zu kennen.

    Du solltest genauer darauf eingehen warum du 2 Pins verwendest. Du erwähnst zwar das es such um einen Backup-Key handelt, aber die Konsequenzen wenn dieser fehlt sollten auch erwähnt werden. Wenn dir nämlich dein Key abhanden kommt und du keinen zweiten definiert hast, dann aber einen neuen Key erstellst und mit diesem ein neues Zertifikat beantragst, kommt niemand mehr auf deine Seite weil dein Hash sich geändert hat. Für den Browser sieht das dann wie ein MitM-Angriff aus.

    Zum Testen kann man auch erst einmal ‚Public-Key-Pins-Report-Only‘ verwenden, damit ist sichergestellt das man niemanden aussperrt falls man einen Konfiguration wählen begangen hat.

  • Sorry, aber schon das berechnen des Hashes für den Public key ist so nicht richtig.

    openssl x509 -pubkey < /PFAD/ZUM/PUBLIC.KEY | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

    wäre es gewesen.

    • Niko

      Doch, das funktioniert schon so wie beschrieben.

      In meinem Befehl gibst du den Pfad zum privaten Schlüssel (.key) an.
      Mit deinem Befehl muss man den Pfad zur Zertifikatsdatei (.crt) angeben.
      Mit beiden Befehlen wird dann der Hash des öffentlichen Schlüssels erstellt. Der erzeugte Hash ist dementsprechend bei beiden Befehlen identisch.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.