Certificate Pinning - TLS weiter absichern

Status
Für weitere Antworten geschlossen.

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Moin moin,
viele nutzen ja (hoffentlich) inzwischen einen verschlüsselten Zugriff auf den Webserver der DS. Seit Snowdens Enthüllungen laufen seit einigen Monaten erste Ergebnisse auf, die einer weiteren Erhöhung der Sicherheit von TLS dienen. DANE gehört dazu, ist aber noch nicht weit verbreitet bei den Hostern, und ebenso Certificate Pinning, dessen Unterstützung auf der Client-Seite inzwischen recht gut ist und wohl sehr schnell erweitert wird, so dass Sinn macht, sich damit einmal zu beschäftigen. Letzteres ist auch insofern interessant, weil man es im Gegensatz zu DANE als Server-Betreiber in seiner eigenen Hand hat.

Certificate Pinning, beschrieben in der RFC 7469, basiert im Rahmen eines TOFU-Ansatzes (Trust On First Use) darauf, dass der Webserver beim ersten Aufruf als weitere Headerinformationen einen oder mehrere Pins liefert, die der Client-Browser für den weiteren Zugriff befolgen wird - auf diese Weise lassen sich also Man-in-the-Middle-Attacken aushebeln. Bei einem solchen Pin handelt es sich um einen Base64-kodierten Hash-Wert (SHA-256) zu einem Zertifikat der Zertifikatskette - entweder direkt für das Server-Zertifikat oder aber eines der Zertifikate bis hin zum CA-Rootzertifikat. Die Header-Informationen sehen in ihrem Aufbau aus wie bspw.
Code:
Public-Key-Pins: pin-sha256="..."; max-age=604800; includeSubDomains
In den "" eingeschlossen findet sich ein entsprechender Pin zum gepinnten Zertifikat. Hinzu kommt, analog wie bei der Strict-Transport-Security-Definition HSTS, eine Angabe in Sekunden, für die der Client diese Zertifikatseinschränkung befolgt, sowie bei Bedarf ein Hinweis, auch Subdomains zu erfassen.
Auf diese Weise sind Man-in-the-Middle-Attacken nach dem ersten Zugriff ausgeschlossen (sofern man innerhalb der Zeitangabe max-age wiederholt zugreift), weil ein zwischengeschalteter SSL-Proxy ein anderes Zertifikat an den Client liefern würde - selbst wenn dieses andere Zertifikat gültig ist, würde der Browser (wenn er Certificate Pinning auswertet) einen Fehler auswerfen und den Zugriff nicht zulassen. Bei den Desktop-Browsern wird Certificate Pinning bisher von Chrome und Firefox unterstützt, dagegen werten IE11, Edge und Apple Safari das bisher nicht aus (ein Zugriff mit diesen Browser ist aber natürlich dennoch möglich, sie ignorieren die Information, könnten so aber auf eine MitM-Attacke hereinfallen). Bei den Mobil-Browsern werten bisher ebenfalls Firefox (Android) sowie Chrome (Android, iOS) gepinnte Zertifikate aus.

Was muss man also tun?
Das Ganze ist recht einfach umzusetzen. Zunächst muss man sich entscheiden, welches Zertifikat man pinnen möchte. Das höchste Maß an Sicherheit erreicht man, wenn man das Server-Zertifikat selbst pinnt - denn eben jenes hat man ja unter voller Kontrolle. Dabei gilt es aber zu beachten, dass ein Browser, der einmal per https zugreift, dabei für die festgelegte Zeit fest auf dieses Zertifikat festgelegt wird. Crasht bspw. der Server und setzt man ihn mit einem neuen Zertifikat auf (weil man zB. nicht an genau dieses bisherige gepinnte Zertifikat über ein Backup herankommt), bleiben die Browser, die zuvor über einen https-Zugriff gepinnt sind, während der festgesetzten Zeit max-age nach dem letzten Zugriff für den https-Zugriff außen vor.
Alternativ kann man natürlich auch ein Intermediate- oder CA-Root-Zertifikat pinnen - was einen Zertifikatswechsel zwar leichter macht, wenn man wieder die gleiche CA nutzt, aber damit auch die Sicherheit wieder etwas reduziert... denn verschafft sich ein Angreifer ebenfalls ein Zertifikat, welches aus dieser CA stammt, bemerkt man den MitM-Angriff wieder nicht. Zumal wird gerade ein Intermediate/Signierzertifikat gelegentlich getauscht, was einem dann ebefalls in die Suppe spuckt.
Erwähnenswert ist es in diesem Zusammenhang, dass die RFC 7469 vorsieht, mehrere Pins auszuliefern, die dann alle geprüft werden, wobei mindestens ein Pin korrekt sein muss - was man natürlich nutzen kann, neben dem Server-Zertifikat auch weitere Teile der Zertifikatskette zu pinnen. Genaugenommen verlangt die RFC allerdings auch, dass mindestens ein Pin nicht Teil der aktuellen Zertifikatskette sein darf (wobei bisher kein Browser diesen Zwang prüft) - dieses ist sozusagen eine Backupmöglichkeit. Man kann nämlich auf diese Weise den Pin eines Reserve-Zertifikats hinterlegen oder - was aus Kostensicht erfreulich ist - den Pin eines entsprechenden CSR (d.h. man kann sich für den Notfall, ohne bereits ein Reserve-Zertifikat bezahlen zu müssen, einen CSR erzeugen und dafür den entsprechenden Pin ermitteln).

Hat man sich entschieden, was genau man pinnen möchte, ermittelt man dazu die entsprechenden Pins. Das kann man bspw. mit OpenSSL tun:
Code:
openssl x509 -in cert.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Dabei ist cert.pem das Serverzertifikat im PEM-Format (auf der DS zu finden unter /usr/syno/etc/ssl/ssl.crt/server.crt ). Die Ausgabe ist dann etwas wie bspw. dJlH...hsnY= (endet aber immer mit einem "=") und stellt den Pin dar. Will man den Pin für einen CSR erzeugen, ersetzt man einfach das x509 durch req .
Alternativ erledigt dieses auch eine kleine JavaScript-Routine unter https://projects.dm.id.lv/s/pkp-online/calculator.html . Dort läßt sich auch gleich die Gültigkeitsdauer in Stufen auswählen und der fertige HTTP Header ausgeben.

Diesen HTTP Header muss man dann in den entsprechenden Webserver verankern (Details). Bei dem Apachen der DS, der standardmäßig das notwendige Modul mod_headers.so lädt, erfolgt das in der ssl-Sektion der Konfig (denn nur für https ist die Festlegung RFC-konform), d.h. um bspw. den User-Apache abzusichern, ergänzt man in der Datei /etc/httpd/conf/extra/httpd-ssl.conf-user ein
Code:
<VirtualHost *:443>
    ServerName *
    ServerAlias *

    SSLEngine on
    ...
   [COLOR=#b22222] Header always set Public-Key-Pins "pin-sha256=\"...\"; pin-sha256=\"...\"; max-age=604800; includeSubDomains"[/COLOR]
    ...
</VirtualHost>
Wichtig ist dabei, die Anführungszeichen, in denen die Pins (hier als ... dargestellt) eingeschlossen sind, mit einem \ zu escapen. Hier sind im Beispiel zwei Pins aufgeführt, die Gültigkeit ist dabei 7 Tage.
Danach ist der Webserver bzw. am besten gleich die DS neuzustarten.
Kleiner Tipp: man sollte vorsichtig anfangen beim Testen und zunächst kleine max-age von vielleicht eine Stunde wählen - ist man sich dann sicherer, kann man das erhöhen auf Wochen bzw. Monate. :)

Diese Informationen kann der interessierte Benutzer ausführlicher in der aktuellen c't 23/2015 auf den Seiten 118-125 nachlesen.
 
Zuletzt bearbeitet:

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Hi,

Anscheinend ist das Modifizieren der Datei doch nicht so einfach ( Konsolenanfänger...). :eek: Jedenfalls scheine ich beim Einfügen der Header Zeile die Datei beschädigt zuhaben. Die Diskstation meldet nach dem Neustart jedenfalls der Dienst httpd- user konnte nicht gestartet werden und die Web Station startet ebenfalls nicht.
Ist es egal, wo in der Datei die Header Zeile ergänzt wird? Oder muss der Header an eine spezielle Stelle?

Gruß Simon

PS: Danke für die gute Erklärung hier!
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Die Änderungen lassen sich am besten mit dem Tool WinSCP durchführen, dann muss man nicht auf die Konsole.
Beschreib mal, wie Du es versucht hast und wie die Datei jetzt aussieht. Die Zeile kannst Du - wie ich es angedeutet habe - zwischen die VirtualHost Definition einfügen, bspw. direkt hinter SSLEngine on - dabei aber aufpassen, nicht innerhalb von Definitionen wie
Code:
<IfDefine ...>
...
</IfDefine>
zu landen. Die Rechte der Datei sollten dabei 0644 bleiben und als Eigentümer/Gruppe root gehören.
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Bearbeitet hab ich die Datei über Putty. In Putty als Root eingeloggt, mit vi /Pfad/Dateiname die Datei in Bearbeitung genommen und sogar, wie du gesagt hast, hinter dem SSLEngine on die Header Zeile eingefügt. Dann mit :wq gespeichert und raus aus Putty, DS neugestartet und da tauchten die Fehler auf. Auch nach entfernen der Header Zeile blieben die Fehler...
Datei ist ansonsten unverändert geblieben.
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Wobei Du jetzt immer noch nicht schreibst, wie genau Deine Datei jetzt aussieht...
Wenn die Fehler auch ohne Header-Zeile kommen, deutet das auch noch auf andere Fehlerquellen hin.
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
vi /etc/httpd/conf/extra/httpd-ssl.conf-user


Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
ServerName *
ServerAlias *

SSLEngine on

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>

Header always set Public-Key-Pins: pin-sha256=\"
BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 fo
CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

<IfDefine HSTS>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfDefine>

Include sites-enabled-user/*.conf
/VirtualHost>
~
~
~
~
- /etc/httpd/conf/extra/httpd-ssl.conf-user [Readonly] 1/28 3%
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
ServerName *
ServerAlias *

SSLEngine on
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
ServerName *
ServerAlias *

- /etc/httpd/conf/extra/httpd-ssl.conf-user [Readonly] 1/28 3%
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
ServerName *
ServerAlias *

SSLEngine on

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>

Header always set Public-Key-Pins: pin-sha256=\"
BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 fo
CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

<IfDefine HSTS>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfDefine>

Include sites-enabled-user/*.conf
/VirtualHost>
~
~
~
~
~
~
~
~
~
~
- /etc/httpd/conf/extra/httpd-ssl.conf-user [Readonly] 1/28 3%
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
ServerName *
ServerAlias *

SSLEngine on

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>

Header always set Public-Key-Pins: pin-sha256=\"
BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 fo
CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

<IfDefine HSTS>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfDefine>

Include sites-enabled-user/*.conf
/VirtualHost>
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~



- /etc/httpd/conf/extra/httpd-ssl.conf-user [Readonly] 1/28



So sieht das aus, wenn ich den vi Befehl auf die Datei anwende. Mit Header Zeilenoch drin...
 
Zuletzt bearbeitet:

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Wenn Du solche Zeilen postest, setz die bitte als code (wenn Du im Posteditor bist, rechts unten auf "Erweitert" klicken und dann kannst Du im Editor Text als code setzen):

code.jpg

Die Datei /etc/httpd/conf/extra/httpd-ssl.conf-user sieht original so aus:
Code:
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
    ServerName *
    ServerAlias *

    SSLEngine on

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>

    BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
    CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    <IfDefine HSTS>
        Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    </IfDefine>

    Include sites-enabled-user/*.conf
</VirtualHost>
Fällt Dir etwas auf in Deiner?
...
<VirtualHost *:443>
ServerName *
ServerAlias *

SSLEngine on

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>

Header always set Public-Key-Pins: pin-sha256=\"
BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 fo
CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

<IfDefine HSTS>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfDefine>

Include sites-enabled-user/*.conf
/VirtualHost>
Der rot markierte Teil ist unvollständig und fehlerhaft (Doppelpunkt, fehlendes Anführungszeichen)! Die Syntax ist, wie eingangs ja bereits geschrieben:
Code:
[COLOR=#b22222]Header always set Public-Key-Pins "pin-sha256=\"...\"; pin-sha256=\"...\"; max-age=604800; includeSubDomains"
[/COLOR]

 
Zuletzt bearbeitet:

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Ergänzend zu meinem Eingangspost sei noch erwähnt, dass Firefox und Chrome offenbar die RFC 7469 insoweit strikt umsetzen, als dass sie Header-Einträge mit nur einem Pin ignorieren - es müssen mindestens 2 Pins angegeben sein. Diese können aktuell noch aus einer Zertifikatskette stammen, denn bisher wird - wie schon erwähnt - nicht die RFC-Vorgabe durchgesetzt, dass ein Pin nicht Teil der aktuellen Zertifikatskette sein darf (ein Pin ist eigentlich als Reserve eingeplant).
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Ich werde morgen anhand deiner gepostet Original Datei meine Fehler ausbügeln. Den Header hatte ich so wie gepostet nicht in der Datei. Hatte ich jetzt so drin stehen lassen, damit du was zur Position sagen kannst.

Mit dem Code Posten werde ich mir für die Zukunft merken!
Danke dir für die Hilfe! Poste dann morgen das Ergebnis!
Hatte übrigens zum Pinnen das Zertifikat und ein Csr vorgesehen?!
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Hatte übrigens zum Pinnen das Zertifikat und ein Csr vorgesehen?!
Das ist eine sinnvolle Lösung - das aktuelle Zertifikat plus ein CSR, den man im Notfall für die Beschaffung eines Neuzertifikats verwenden kann, welches dann exakt die Pin trägt, die man aus dem CSR ausrechnet.
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Nochmal alles korrigiert, leider ohne Erfolg. Müsste es mit Putty machen, da ich mit Win SCP kein Root Zugriff bekomme.
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Dann hast Du weiterhin Syntax-Fehler darin. Poste bitte den Inhalt der Datei.
Mit WinSCP kommst Du auch hinein - stell mal die Verbindungsdaten analog der im Screenshot ein (mit der IP Deiner DS natürlich).

scp2.jpg
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Rich (BBCode):
Listen 443

Include conf/extra/httpd-ssl.conf-common

NameVirtualHost *:443

#INCLUDE_SSL_VHOST_CONF#

<VirtualHost *:443>
    ServerName *
    ServerAlias *

    SSLEngine on

     Header always set Public-Key-Pins "pin-sha256=\"...=\";pin-sha256=\"...=\";max-age=600;includeSubDomains"

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>
    

    BrowserMatch ".*MSIE [2-5]\..*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
    CustomLog /dev/null "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    

    <IfDefine HSTS>
        Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    </IfDefine>

    Include sites-enabled-user/*.conf
/VirtualHost>

So sieht die Datei jetzt bei mir aus. Und mit deinem Hinweis kam ich auch über WinSCP als root an die Datei ran!
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Bei den
pin-sha256=\"...=\

stehen statt der ... aber in Wirklichkeit die Pins, die Du berechnet hast, oder etwa nicht?
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
:D Na klar! da stehen die beiden Pins statt der 3 Punkte!
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Und die Rechte der Datei sind wie? Dazu kannst Du die Datei in WinSCP markieren und auf "Eigenschaften" klicken.
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Das sieht soweit in Ordnung aus. Wie sieht denn die Fehlermeldung aus?
Und wie lauten die Pins, den Du berechnet und in der Headerzeile eingetragen hast? Die sind ja nicht geheim.
 

Angwulf

Benutzer
Mitglied seit
27. Sep 2014
Beiträge
33
Punkte für Reaktionen
0
Punkte
6
Das ist die Fehlermeldung die die DS auswirft:
Systeminterner Dienst [httpd-user] konnte nicht gestartet werden. Bitte kontaktieren Sie den Synology Kundendienst, um Unterstützung zu erhalten.

Die Pins sind eh für jedermann sichtbar,wenn die dann mal im Einsatz sind^^, kann ich hier also posten?
 

Frogman

Benutzer
Mitglied seit
01. Sep 2012
Beiträge
17.485
Punkte für Reaktionen
8
Punkte
414
Ja, die Pins sind - wie ich oben ja schrieb - ein Hash-Wert auf Deinem gepinnten (öffentlichen) Zertifikat oder öffentlichen CA-Zertifikaten. Die kann jeder selbst ausrechnen, wenn er Deine Seite aufruft.
 
Status
Für weitere Antworten geschlossen.
 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat