Wie der Heise-Artikel
http://www.heise.de/security/artikel/Zukunftssicher-Verschluesseln-mit-Perfect-Forward-Secrecy-1923800.html sehr schön aufzeigt, ist Perfect-Forward-Secrecy aktueller denn je.
Ich habe mir daher die Frage gestellt, wie man dies nun unter Debian Wheezy einrichten kann, sodass der SSL Labs Test (
https://www.ssllabs.com/ssltest/) anschließend mit der Seite zufrieden ist.
Dabei ist zunächst aufgefallen, dass das mit Debian Wheezy ausgelieferte Apache 2.2 noch keine ECDHE-Verfahren unterstützt. Trägt man nämlich "SSLCipherSuite ECDHE-RSA-AES256-SHA" in die mods-available/ssl.conf ein und beschränkt so die serverseitg verfügbaren Ciphern auf ECDHE-RSA-AES256-SHA, so startet der Apache2 HTTPS Server zwar, aber es kann anschließend keine SSL Verbindung aufgebaut werden, da keine unterstützte Cipher gefunden werden konnte. OpenSSL unterstützt das Verfahren jedoch schon (für Überprüfung "openssl ciphers -V ECDHE-RSA-AES256-SHA" ausführen). Die ECDHE-Verfahren sind jedoch wegen ihrer Geschwindigkeit und zur Unterstützung des Internet Explorers 10 interessant.
Das mit Debian Wheezy ausgelieferte nginx (Version 1.2) unterstützt jedoch bereits die ECDHE-Verfahren und wie der Apache2 auch Server Name Indication (SNI). Daher lässt es sich bequem als HTTPS-Reverse-Proxy einsetzen. Um Perfect Forward Secrecy mit dem Internet Explorer 10 zu erreichen, müssen die ECDHE-Verfahren im Server besonders priorisiert werden. Um die Konfiguration des Apache-Servers einfacher zu gestalten, fügt man dem loopback-Interface einfach eine weitere IP (127.0.0.2) hinzu und lässt den Apache Server dort auf Port 443 mit HTTPS lauschen. So brauchen weder Ports umgeschrieben zu werden (vorausgesetzt dass der Dienst auch auf Port 443 angeboten wird) noch die Information, dass es sich um eine SSL Verbindung handelt, irgendwie im Apache aus HTTP-Request-Headern wieder hergestellt zu werden.
Beispielkonfiguration:
server {
### server port and name ###
listen public-ip:443 ssl;
server_name ssl.example.org;
### SSL log files ###
access_log /var/log/nginx/ssl-access.log;
error_log /var/log/nginx/ssl-error.log;
### SSL cert files ###
ssl_certificate /etc/ssl/test.example.org.chain;
ssl_certificate_key /etc/ssl/test.example.org.key;
### Add SSL specific settings here ###
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:RC4:HIGH:!MD5:!aNULL:!EDH;
ssl_prefer_server_ciphers on;
keepalive_timeout 60;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
### We want full access to SSL via backend ###
location / {
proxy_pass https://127.0.0.2:443;
### force timeouts if one of backend is died ##
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
### Set headers ####
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
### Most PHP, Python, Rails, Java App can use this header ###
proxy_set_header X-Forwarded-Proto $scheme;
add_header Front-End-Https on;
### By default we don't want to redirect it ####
proxy_redirect off;
}
}
Da der nginx Server Name Indication (SNI) unterstützt, kann man auch einfach mehrere solcher Server-Direktiven in die Konfigurationsdatei packen - es wird dann automatisch der passende Host ausgewählt. Durch die Weiterleitung des HTTP-Host-Headers weis anschließend auch der Apache2 Server, welche Seite er ausliefern soll.
Im Apache2 kann man dann noch Strict Transport Security für alle SSL-Seiten aktivieren:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Der Header soll nur bei HTTPS-Aufrufen zurück geliefert werden und weist den Browser an, zukünftig (hier: 1 Jahr) die Webseite immer mit HTTPS zu besuchen.
Damit bekommen wir jetzt bei SSL Labs ein A-Rating
[UPDATE]
Marcel hat mich noch auf zwei Aspekte hingewiesen, die ich hier natürlich nicht verschweigen will:
- Durch die Umleitung mittels nginx tauchen im Apache-Log die Client-IPs für SSL-Verbindungen nicht mehr auf. Auch Anwendungen müssten ggf. auf den X-Forwarded-For Header ausweichen. Allerdings lässt sich auch der Apache Webserver entsprechend konfigurieren, dass er den X-Forwarded-For Header mit ins Log schreibt. Dies betrifft im Besonderen auch die Bindung von Session-IDs an Client-IPs!
- nginx prüft das Zertifikat bei der Weiterleitung nicht. Bei loopback-Verbindungen ist das nicht ganz so kritisch und immernoch besser als einfaches HTTP.
[/UPDATE]
[UPDATE]
Weitere Informationen gibt es dazu auch auf
https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy
[/UPDATE]
Trackbacks