HSTS verstehen und konform einrichten

Alle nicht sicheren Verbindungen umleiten

Laut RFC 6797 sind alle unsicheren Verbindung auf eine sichere Verbindung umzuleiten. Dabei ist zu beachten, dass der Host hierbei nicht geändert werden darf. Wird bei einer Umleitung von HTTP auf HTTPS der Host mitgeändert, dann wird der HSTS Header vom Browser ignoriert!

Folgende Umleitung ist daher falsch:

http://www.allius.de ==> https://allius.de

und muss in zwei Umleitung aufgeteilt werden:

http://www.allius.de ==> https://www.allius.de
https://www.allius.de ==> https://allius.de

Dabei ist zu beachten, dass bei der ersten Umleitung bereits HSTS aktiviert werden muss und somit auch ein gültiges Zertifikat für die Domaine www.allius.de benötigt wird.

Für Nginx benötigt man für die konforme Umleitung zwei Serverblöcke:

server {
    listen      80;
    listen      [::]:80;

    server_name allius.de www.allius.de;

    return 301 https://$host$request_uri;
}

server {
    listen      443 http2;
    listen      [::]:443 http2;

    server_name www.allius.de;

    error_page 497 =301  https://$host$request_uri;
    add_header Strict-Transport-Security $hsts_header always;

    return 301 https://allius.de$request_uri;
}

Der erste Block leitet alle HTTP Requests auf die HTTPS um, ohne den Host zu ändern. Durch Verwendung der Variable $host im return Statement, kann der Block auch für mehrere Webserver (hier: allius.de und www.allius.de) benutzt werden.

Der zweite Block leitet HTTPS Request auf die Zieldomain ‚allius.de‘ um. Der HSTS Header wird ebenfalls gesetzt. Was es mit der Zeile ‚error_page 497…‘ auf sich hat, erkläre im nächst Absatz.

Sonderfall HTTP über Port 443

Wie zuvor schon angesprochen, sind alle unsicheren Verbindungen für eine HSTS konforme Implementation umzuleiten. Wie sieht es mit folgenden Fall aus:

http://allius.de:443/index.php

Hier wird der Browser angewiesen, die Seite allius.de/index.php über den Port 443 mit dem unsicheren Protkoll HTTP zu laden. In der Regel wird dies nicht funktionieren und der Browser meldet einen Fehler oder ein Timeout. Im Webserver wird das Klartext HTTP Paket an den TLS Stack weitergeleitet und es wird eine Fehlerbehandlung angestoßen.

Aus Security Sicht, sind Ausnahme- und Fehlerbehandlungen immer besonders kritisch. Wird unser obiger Fall beispielsweise im Log des Webservers protokolliert, führt dies durch den Zugriff auf die Festplatte zu einer erhöhten Auslastung des Servers und dies kann von einem Angreifer ausgenutzt werden. Auch sind Fehlerbehandlungen häufig nicht so gut getestet wie der Normalbetrieb. Somit schleichen sich hier auch schneller Fehler ein, die von Angreifern wieder genutzt werden.

Lösung für nginx

Nginx erkennt den obigen Protokollfehler und behandelt diesen mit einem internen, nicht standarisierten HTTP Fehlercode 497. Dieser wird in den meisten Implementationen nicht behandelt. Auch auf meiner Synology Diskstation unter DSM 6.2 ist dies so.

Man kann den Fehler mit folgender Zeile:

error_page 497 =301  https://$host$request_uri;

HSTS konform behandeln. Wird nun versucht, eine HTTP Verbindung über den TLS Port 443 zu starten, wird dies mit einer permanten Umleitung (HTTP Code 301) auf die HTTPS Seite beantwortet.