Starke und sichere SSL Verschlüsselung mit NGINX

Verschlüsselung ist gut – sichere Verschlüsselung ist besser!

In diesem Artikel werden wir unsere Verschlüsselung unter NGINX verstärken und somit sicherer machen. Wir werden so umstellen, dass nur noch Protokolle, Cipher Suites und Verschlüsselungsalgorithmen genutzt werden, welche – Stand Heute – als sicher gelten, also keine Schwachstellen vorhanden sind.

Ziel ist es, Angriffe wie Heartbleed, BEAST, Poodle und Konsorten zu verhindern,  wir werden nur Cipher Suites verwenden, welche Forward Secrecy bieten und SSL v3 und älter unterbinden.

Wir möchten als Ergebnis ein A+ Rating beim SSL Labs Test erhalten.

Bitte beachtet, dass ihr damit möglicherweise einige veraltete Browser von eurer Webseite ausschließt, z.B. Internet Explorer 8 und älter unter Windows XP. Diese Browser unterstützen in der Regel aber sowieso kein SNI (virtuelles SSL Hosting). Im Sinne der Sicherheit sollte das akzeptabel sein.

Ausgangslage

Zum Start nehmen wir eine Webseite auf einem vServer welche mittels EasyEngine eingerichtet wurde.

Die URL dieser Seite werfen wir in den SSL Labs Test und erhalten folgendes Ergebnis:

SSL Repost Ausgangslage

Als Overall Rating erhalten wir ein ‘B’ – wobei wir schon sehen könne, dass unser Zertifikat 100% erreicht, die Protokoll Unterstützung sowie die Cipher Stärke sehr gut bewertet sind.

Auf Grund des schwachen Diffie-Hellman Schlüssel Austausches, wird die Bewertung aber auf ‘B’ begrenzt. Dieses wollen wir durch unsere Anpassungen ‘korrigieren’.

Wir nehmen Änderungen an der Konfiguration eures Servers vor – bitte legt euch ein Backup aller Konfigurationsdateien an – und immer daran denken: Alle Änderungen auf eigene Gefahr!

NGINX Anpassen

Dieses HowTo basiert auf einer Einrichtung mit EasyEngine – lässt sich aber auf alle NGINX Einrichtungen anwenden, die Pfade sind dann allerdings möglicherweise abweichend!

Grundsätzlich bestehen 2 Möglichkeiten die Einstellungen anzupassen:

  1. Global für alle per NGINX bedienten Domains
  2. Für jede Domain einzeln

Wenn ihr das Global einstellen möchtet, dann ändert ihr die Einstellungen in der NGINX Konfigurationsdatei unter /etc/nginx/nginx.conf

##
# SSL Settings
##
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

Einige der hier im HowTo besprochenen Anpassungen sind bei EasyEngine bereits voreingestellt!

Solltet ihr das per Domain anpassen, dann ändert ihr das in der Konfigurationsdatei der jeweiligen Domain, und zwar im { server } Block,  die Anpassungen werden im SSL Teil vorgenommen!

Ihr findet die Konfigurationsdatei hier: /var/www/domain.de/conf/nginx/ssl.conf – bitte domain.de gegen eure Domain austauschen.
Bei Debian Standard Einrichtung unter /etc/nginx/sites-available/domain.de – bei CentOS unter /etc/nginx/nginx.conf.

Der Inhalt der Konfiguration sieht wie folgt aus:

listen 443 ssl http2;
ssl on;
ssl_certificate /etc/letsencrypt/live/test1.iptool.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test1.iptool.de/privkey.pem;

Diese Konfiguration passen wir nun an:

SSLv2 und SSLv3 abschalten

SSLv2 und SSLv3 sind unsicher, wir werden diese abschalten und nur die Protokolle TLS v1 v1.1 und v1.2 unterstützen, dazu fügen wir folgende Zeile zur Konfiguration hinzu:

ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

TLSv1 kann von einem Angreifer auf SSL v3 heruntergestuft werden – das ist allerdings kein Problem, da wir SSL v3 nicht unterstützen. Man kann auch überlegen TLSv1 aus der Konfiguration zu entfernen.

Bei EasyEngine kann dieser Punkt übersprungen werden, außer ihr möchtet TLSv1 entfernen!

Cipher Suites anpassen

Die Cipher Suites bestimmen, welche Algorithmen zum Aufbau eine SSL Verbindung verwendet werden sollen, mit der folgenden Änderung beschränken wir die Aushandlung zwischen Client und Server auf Cipher Suites welche Forward Secrecy unterstützen.

Mittels ssl_prefer_server_ciphers on stellen wir außerdem sicher, dass beim Verbindungsaufbau die Server Wünsche bzgl. Cipher Suite benutzt werden. Nnormalerweise werden die des Clients genutzt, aber das möchten wir verhindern.

Die Cipher Suites in EasyEngine sind bereits gut konfiguriert, wenn gewünscht, dann kann man diese noch weiter einschränken

ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

Bei nicht EasyEngine Installationen bitte noch diese beiden Parameter einstellen bzw. überprüfen:

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:20m;

Wenn ihr ältere Clients unterstützen möchtet, dann könnt ihr, dem Mozilla SSL Konfigurator folgen und die folgenden Cipher Suites Verwenden (was auch der Default Einstellung bei Easy Engine entspricht!)

ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

Diffie Hellman Schlüssel anpassen

Wir richten nun einen 4096bit langen Diffie Hellman Schlüssel ein, damit passen wir die Schlüssellänge so an, dass ein mindestens gleichlanger Schlüssel wie in den Zertifikaten verwendet wird – und gleichzeitig ersetzen wir den mitgelieferten Schlüssel durch unseren eigenen.

Man kann auch einen 2048bit langen Schlüssel erstellen, dann einfach 4096 durch 2048 ersetzen

cd /etc/ssl/certs
openssl dhparam -out dhparam_4096.pem 4096

Die Generierung dauert ziemlich lange – genug Zeit für einen Kaffee!

Diesen Schlüssel definieren wir dann in der globalen NGINX Konfigurationsdatei!
Hier fügen wir im SSL Settings Teil die folgende Zeile hinzu

ssl_dhparam /etc/ssl/certs/dhparam_4096.pem;

HSTS – HTTP Strict Transport Security einstellen

Mittels HSTS teilt der Server dem Browser beim Verbindungsaufbau mit, dass er innerhalb einer angegebenen Zeit (max-age), nur noch verschlüsselt mit dem Server kommunizieren soll.

Daraufhin wird jede unverschlüsselte Verbindung, sowie jede Verbindung mit einem ungültigen Zertifikat abgebrochen. Dadurch lassen sich Man in the Middle Attacken vermeiden.

Der max-age Parameter gibt in Sekunden an, wie lange der Browser noch nur verschlüsselt kommunizieren soll.
Wir konfigurieren ein max-age von 6 Monaten.

add_header Strict-Transport-Security max-age=15768000;

Diese Einstellung nehmen wir per Domain vor, also bitte in der /var/www/domain.de/conf/nginx/ssl.conf eintragen!

Solltet ihr planen, die Webseiten wieder per HTTP auszuliefern, dann bitte einige Zeit vor dieser Umstellung das max-age auf 1 Sekunde einstellen, ansonsten kann ein wiederkehrender Besucher erst nach Ablauf der max-age wieder auf die Webseite zugreifen!

Abschluss und erneuter SSL Labs Test

Die Konfiguration ist nun fertig und wir starten NGINX neu. Danach besuchen wir die SSLABS Testseite um den Erfolg unserer Anpassungen zu überprüfen. Das Ergebnis sollte nun so aussehen:

SSL Labs Ende

Ihr solltet jetzt auch bei einem A+ Rating gelandet sein, wenn nicht, dann stimmt an eurer Konfiguration etwas nicht 🙂

Damit sind wir am Ende angelangt – Viel Erfolg bei euren Anpassungen!

Michael Kokott