HSTS – Was es ist, wie es funktioniert und wie man es in Apache einrichtet

HSTS steht für HTTP Strict Transport Security und ist ein HTTP-Header bei dem der Webserver dem anfragenden Browser mitteilt, das alle Verbindungen nur ueber SSL/TLS aufgebaut werden sollen.
HSTS soll „Man-in-the-middle“ Attacken abwehren oder erschweren. Das Angriffsszenario besteht darin, dass Nutzer in der Regel nie

https

in den Webbrowser eingeben, sondern immer nur

example.net

Die Weiterleitung von http:// zu https:// macht der Webserver. Das sieht dann zum Beispiel so aus:
ohne_hsts

Man kann sehen, dass die erste GET Anfrage mit einem HTTP 302 Weitergeleitet wird und die zweite dann ein 200 OK zurueck liefert. Der Webserver ist in diesem Fall so konfiguriert, das alles was per HTTP reinkommt, automatisch auf HTTPS umgeleitet wird:

<VirtualHost *:80>
        ServerAdmin webmaster@jan-von.de
        ServerName mail.jan-von.de
        DocumentRoot /var/www/empty
 
        RewriteEngine on
        RewriteCond %{HTTP:X-Forwarded-Proto} !https
        RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
 
        CustomLog /var/log/apache2/mail.jan-von.de-access.log combined
</VirtualHost>

Genau hier liegt auch das Problem. Man kann sich in einem fremden Netz befinden, zum Beispiel einem unbekannten oeffentichen WLAN, dort kann die HTTP Anfrage abgefangen und der HTTPS Aufruf auf einen alternativen Server weitergeleitet werden.

Hier kommt HSTS ins Spiel. Der Server teilt dem Webbrowser mit, dass er sich bitte fuer eine bestimmte Zeit (zum Beispiel ein Jahr) daran erinnern soll, das diese Webseite nur noch ueber HTTPS aufgerufen werden soll.

In Apache muss dafuer das Headers-Modul aktiviert sein:

a2enmod headers

und anschliessend fuegt man in den HTTPS vhost die folgende Zeile ein:

Header always set Strict-Transport-Security "max-age=31556926"

Der Parameter max-age wird in Sekunden gesetzt. 31556926 Sekunden sind 365 Tage. Ein weiterer Parameter den man optional noch mit Komma Semikolon separiert dahinter haengen kann ist includeSubDomains. Dafuer muss aber sichergestellt sein, dass auch alle Subdomains per HTTPS erreichbar sind.
Weiter muss man aufpassen, dass die entsprechenden vhosts auch die angegebene Zeit, also zum Beispiel ein Jahr lang per HTTPS erreichbar sind, ansonsten kann es zu Fehlermeldungen kommen.

Wenn man dann HSTS aktiviert hat und eine Webseite aufruft die es unterstuetzt, dann kann man schoen sehen, wie der Browser gleich HTTPS nimmt und gar nicht erst HTTP probiert.

mit_hsts

Weiteres zu dem Thema z.B. unter:

Apache2 mod_proxy und mod_rpaf

Mein Webserver ist in einem internen Netz und davor sitzt ein Apache Webserver der die Anfragen mittels mod_proxy nach hinten weiterreicht. Damit in den Logfiles des internen Webservers dennoch die korrekten IP Adressen auftauchen muss dort das Apache Modul rpaf installiert und konfiguriert werden.

Vor der Installation und Konfiguration sehen bei mir die Logeintraege wie folgt aus:

[Sat Nov 09 18:32:14 2013] [error] [client 10.10.10.10] File does not exist: /var/www/foobar

Die Installation des Moduls erfolgt bei Debian aus den Paketquellen:

apt-get install libapache2-mod-rpaf

Anschliessend muss das Modul aktiviert werden:

a2enmod rpaf

Konfiguriert wird es in der Datei /etc/apache2/mods-enabled/rpaf.conf. Dort muss die IP des oder der Proxy-Server entsprechend hinzugefuegt werden. In dem Beispiel oben ist 10.10.10.10 der Proxy-Server und wird entsprechend unter RPAFproxy_ips hinzugefuegt:

<IfModule rpaf_module>
    RPAFenable On
 
    # When enabled, take the incoming X-Host header and
    # update the virtualhost settings accordingly:
    RPAFsethostname On
 
    # Define which IP's are your frontend proxies that sends
    # the correct X-Forwarded-For headers:
    RPAFproxy_ips 10.10.1.2
 
    # Change the header name to parse from the default
    # X-Forwarded-For to something of your choice:
#   RPAFheader X-Real-IP
</IfModule>

Nach dem Neustart des Apache Webservers steht dann die korrekte IP in der Logdatei:

[Sat Nov 09 18:46:32 2013] [error] [client 77.176.69.123] File does not exist: /var/www/foobar

HowTo: multiple Apache2 vhosts mit unterschiedlichen SSL-Zertifikaten

Die Aufgabe: in Apache bei verschiedenen vhosts verschiedene SSL-Zertifikate fuer die Verschluesselung definieren.
Das Problem: mit mod_ssl laesst sich das ganze nicht so einfach realisieren.
Die Ursache: vhosts basieren auf Basis von HTTP-Headers, SSL liegt ein Layer darunter. Die Verbindung wird gesichert bevor HTTP gesprochen wird. Der Server kann bei Verbindungsaufbau nicht wissen welchen vhost er danach bedienen soll, deswegen kann er das richtiger Zertifikat nicht auswaehlen.
Die Loesung: mod_gnutls
HowTo: das ganze unter Debian Lenny

Ich gehe an dieser Stelle davon aus, dass man bereits SSL-Zertifikate generiert hat (blubs).

Als naechstes ist es nun wichtig das Modul zu installieren, anzupassen und zu aktivieren:

aptitude install libapache2-mod-gnutls

Danach die /etc/apache2/mods-available/gnutls.conf anpassen:

<IfModule mod_gnutls.c>
  GnuTLSCache dbm /var/cache/apache2/gnutls_cache
 
  AddType application/x-x509-ca-cert .crt
  AddType application/x-pkcs7-crl    .crl
 
  GnuTLSCacheTimeout 300
  NameVirtualHost *:443
</IfModule>

und das Modul aktivieren:

a2enmod gnutls

Nun noch die Zeile:

Listen 443

zu der /etc/apache2/ports.conf hinzufuegen und dabei darauf achten, dass die Zeile vor der „Listen 80“ steht, da es sonst in der /var/log/apache2/error.log zu den folgenden Zeilen kommen kann:

[Sun Dec 05 14:37:06 2010] [error] [client ::1] GnuTLS: Handshake Failed (-8) 'A record packet with illegal version was received.'

Nun koennen die vhosts entsprechend eingerichtet werden. Hier ein generisches Beispiel fuer einen vhost:

<VirtualHost *:443>
    ServerAdmin webmaster@example.net
    ServerName www.example.net
    ServerAlias example.net
    DocumentRoot /var/www/example.net/
 
    <Directory /var/www/example.net/>
        Options +Indexes
    </Directory>
 
    GnuTLSEnable on
    GnuTLSCertificateFile /etc/ssl/myCA/private/www.example.net-key-cert.pem
    GnuTLSKeyFile /etc/ssl/myCA/private/www.example.net-key-cert.pem
    GnuTLSPriorities SECURE:!MD5
 
    CustomLog /var/log/apache2/example.net-access.log combined
</VirtualHost>

Nach einem Neustart von Apache2 kann nun per https auf den gewuenschten vhost zugegriffen werden, viel Spass beim Einrichten des zweiten und freien wenns klappt!