Tech Blog.

Thoughts, stories, ideas.

Webserver security

7. April 2017

Im Bereich von Webserver sind viele Möglichkeiten vorhanden, um Verbindungen besser abzusichern, aber auch Cross-Site Attacken zu verhindern.

SSL

Es werden hier zuerst die einfachen SSL/TLS Konfigurationen, danach noch erweiterte SSL/TLS Features, wie HSTS und OCSP aufgezeigt. Grundsätzlich wird empfohlen immer aktuelle Protokolle und Cipher Suites, zum Beispiel aus dem Mozilla Wiki, zu kopieren. Diese werden oft nachgeführt und es sind nicht nur verschiedene Cipher Suites aufgelistet, sondern auch die jeweilige Kompatibilitätsliste dazugegeben.

Die Konfiguration “Modern” ist zwar anstrebenswert, jedoch werden sich dadurch ältere Clients oft nicht mehr auf die Server verbinden können. Daher empfiehlt es sich eher, die Konfiguration “Intermediate” zu nutzen. Im Mozilla Wiki und bei Cipherli.st sind auch immer die Konfigurationen verschiedener Software gegeben. Cipherli.st mag zwar übersichtlicher sein und mehr Beispiele aufzeigen, die Cipher Suites sind jedoch längst nicht so durchdacht, wie im Mozilla Wiki. Daher sollten die Cipher Suites eher aus dem Mozilla Wiki übernommen werden.

Nginx

server {
listen 80 default_server;
listen [::]:80 default_server; # Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
} server {
listen 443 ssl http2;
listen [::]:443 ssl http2; # Certs sent to the client in SERVER HELLO are concatenated
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /path/to/dhparam.pem; # Intermediate configuration, tweak to your needs
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on; # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000; # OCSP Stapling # Fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on; ## Verify chain of trust of OCSP responses
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; resolver <IP DNS resolver>; [...]
}

Nginx erwartet als CA Zertifikat (Parameter ssl_certificate) das Zertifikat aller Intermediate CAs und das eigene Server Zertifikat (alles im PEM Format). Diese können einfach zusammen kopiert werden (das erste Zertifikat im File sollte das Server Zertifikat sein).

Apache

<VirtualHost *:443>
[...]
SSLEngine on
SSLCertificateFile /path/to/signed_certificate_followed_by_intermediate_certs
SSLCertificateKeyFile /path/to/private/key # Uncomment the following directive when using client certificate authentication #SSLCACertificateFile /path/to/ca_certs_for_client_authentication # HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always set Strict-Transport-Security "max-age=15768000"
[...]
</VirtualHost> # Intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off # OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)

Testen

Um HTTPS Server zu testen, eignet sich Qualys SSL Labs am besten. Dort sind auch bei neuen Attacken schnell Tests eingebaut, welche die Server auf die Vulnerabilities testen. Alternativ kann hierzu auch Hardenize verwendet werden. Dieses befindet sich momentan aber noch in einer Testphase.

Es ist möglich, mit openssl manuell zu testen, der folgende Test kann dabei einfach mit den eigenen Parameter erweitert werden. Dies ist nur ein Basis Command, welcher den Inhalt des Server Zertifikates in Textform darstellt. Es kann damit auch die Cipher Suite getestet werden, da dies aber lange und vielzählige Commands sind, wird empfohlen, dies mit den vorhandenen Diensten zu machen. Ist dies nicht gewünscht oder technisch nicht möglich, kann z.B. SSL Decoder lokal installiert und ausgeführt werden, die Sources dazu befinden sich auf GitHub ist.

$ openssl s_client -connect example.com:443 2>/dev/null </dev/zero | openssl x509 -noout -text

Weitere Parameter sind in der Manpage von s_client und x509 dokumentiert.

Weitere Features im Bereich von SSL/TLS

Webserver können auch Headers für Strict-Transport-Security und Public-Key-Pins ausliefern. Welche gewünscht sind und welche nicht, hängt vom Einsatz ab.

Strict-Transport-Security – RFC 6797

Die Idee dahinter ist, dass wenn ein Browser mit einer Webseite einmal eine Verbindung hatte, zukünftig weis, dass immer HTTPS genutzt werden soll. Den Wert, der vom Webserver gesendet wird, ist die Anzahl Sekunden für wie lange diese Einstellung gültig sein soll.

Public-Key-Pins – RFC 7469

Mit Public Key Pinning (HPKP) wird die Subject Public Key Info im Zertifikat angegeben (ist schon im Certificate Signing Request), welcher der Webserver ausliefern muss. Mit der stark wachsenden Verbreitung von Let’s Encrypt ist dies nicht mehr so simpel, da dort die Zertifikate automatisch erneuert werden. Wird immer der selbe Certificate-Signing-Request verwendet, funktioniert HPKP, dies muss jedoch so vom Let’s Encrypt Client umgesetzt sein. Das Verständnis von HPKP ist enorm wichtig, um dieses korrekt umzusetzen. Werden Fehler gemacht, können Webseiten gegebenenfalls von gewissen Clients über längere Zeit nicht mehr genutzt werden. Backup Keys sind Pflicht und werden auch vom RFC vorausgesetzt. Backups des Servers dürfen natürlich nicht vergessen gehen.

Weiterführendes

Webserver sollten auch gewisse Headers, z.B. gegen Cross-Site-Scripting, ausliefern. Welche gewünscht sind und welche nicht, hängt vom Einsatz ab. securityheaders.io bietet die Möglichkeit gängige Headers zu testen:

  • Content-Security-Policy
  • X-Frame-Options
  • X-XSS-Protection
  • X-Content-Type-Options

Diese Optionen können Auswirkungen auf die Webseite haben und brauchen teilweise spezifische Anpassungen.

Eine mögliche Konfiguration von Nginx sieht wie folgt aus (in der server Section):

add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
add_header Content-Security-Policy "script-src 'self'";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";

Die entsprechenden Werte sind per Default konfiguriert und sollten so angepasst werden, dass die Seite auch funktioniert. Gängige Browser zeigen in den Developer Tools beim Laden der Seite, was verhindert wurde. Dadurch kann darauf geschlossen werden, welche Werte noch hinzugefügt werden müssen.

Links