Ubuntu Server 14.04 – Webserver Apache absichern

Durch die zunehmende Anzahl und gleichzeitig steigende Qualität böswilliger Angriffe auf Websites werden immer wieder neue Schwachstellen in Webserverkonfigurationen offengelegt. Neben der als selbstverständlich anzusehenden Basisabsicherung mit dem verschlüsselnden „HyperText Transfer Protocol Secure“ HTTPS sollten daher zusätzliche Sicherheitsvorkehrungen getroffen werden. Um zeitnah auf neue Sicherheitslücken reagieren zu können, sind die Schutzmethoden durch regelmäßige Tests zu überprüfen und bei Bedarf anzupassen und / oder zu ergänzen.
Im nachfolgenden Beitrag werden wir den Webserver Apache ausgehend von einer HTTPS-Basiskonfiguration auf Sicherheit hin optimieren. Serverseitig schließen wir hierzu alle Übertragungsprotokolle bis auf TLS 1.2 aus und lassen nur Verschlüsselungs- und Authentifizierungverfahren mit ephemeralen Elliptic Curve Diffie-Hellman-Schlüsseln zu. Damit gewährleisten wir „Perfect Forward Secrecy“ PFS und verhindern DROWN-, Poodle- und Logjam-Attacken. Durch das Einfügen zusätzlicher HTTP-Antwortheader aktivieren wir clientseitig „HTTP Strict Transport Security“ HSTS zur Abwehr von Man-in-the-Middle-Angriffen und schützen uns mit einer „Content Security Policy“ CSP in Kombination mit weiteren Headern vor Clickjacking- und Cross-Site-Scripting-Attacken. Zur Analyse der Wirksamkeit der Schutzmaßnahmen nutzen wir den SSL Server Test von Qualisys und den HTTP-Headertest SecurityHeaders.io von Scott Helme.
[Update 29.08.2016 Anfang]
Einen weiteren Online-Sicherheitscheck, in den auch Ergebnisse anderer Tests einfließen, bietet Mozilla mit dem Projekt Observatory an. Von diesem Programm gibt es auch eine Kommandozeilenversion httpobs, die für einen regelmäßigen automatisierten Check genutzt werden kann.
[Update 29.08.2016 Ende]
Dieser Artikel ist eine Ergänzung des Beitrags zur LAMP-Server-Installation. Hierin haben wir in der Apache-Konfiguration einen virtuellen Host www.test.local für die HTTPS-Standardwebsite eingerichtet. Eine automatische Umleitung von http://www.test.local auf https://www.test.local verhindert unverschlüsselte Zugriffe. Die Testdomain test.local dient dabei lediglich als Platzhalter für eine reale Domain.

Voraussetzungen

Wir haben unseren Server z. B. gemäß den Anleitungen zur Ubuntu-Server-Basisinstallation und zur LAMP-Server-Installation installiert und konfiguriert und durch Updates / Upgrades auf den neuesten Stand gebracht. Die Befehle führen wir mit Root-Rechten aus, z. B. nach Öffnen einer Rootshell mit sudo -i.

Website mit SSL Server Test analysieren

Für eine Sicherheitscheck unserer Website www.test.local eignet sich der SSL Server Test von Qualisys, den wir im Browser wie folgt aufrufen:

https://www.ssllabs.com/ssltest/analyze.html?d=www.test.local&latest

Die Analyse kann wegen des Umfangs der durchgeführten Prüfungen mehrere Minuten dauern, liefert dafür aber eine Vielzahl konkreter Hinweise auf mögliche Schwachstellen. Bei unserem Testsystem erhielten wir folgende Sicherheitswarnungen:

...
Protocols
...
SSL 3 2   INSECURE 	Yes
...
Cipher Suites (sorted by strength as the server has no preference; deprecated and SSL 2 suites at the end)
...
TLS_RSA_WITH_RC4_128_SHA (0x5)   INSECURE 	128
...
TLS_ECDHE_RSA_WITH_RC4_128_SHA (0xc011)   ECDH secp256r1 (eq. 3072 bits RSA)   FS   INSECURE 	128
...
Protocol Details
...
POODLE (SSLv3) 	Vulnerable   INSECURE (more info)   SSL 3: 0xa
...
RC4 	Yes   INSECURE (more info)
...
Forward Secrecy 	With some browsers (more info)
...

Apache-SSL-Konfiguration anpassen

Zur Erhöhung der Sicherheit nehmen wir zunächst zwei Änderungen in der Konfigurationsdatei /etc/apache2/mods-available/ssl.conf des SSL-Moduls von Apache vor:

...
#SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
SSLCipherSuite EECDH:!SHA1
...
#SSLProtocol all
SSLProtocol TLSv1.2
...

Mit der SSLCipherSuite-Anweisung legen wir fest, welche kombinierten Verschlüsselungs- und Authentifizierungverfahren („Cipher Suites“) unser Server dem Client für eine gesicherte SSL/TLS-Verbindung anbietet. Apache greift dabei auf die vom Programmpaket OpenSSL zur Verfügung gestellten Cipher-Suites zurück, die wir uns mit openssl ciphers anzeigen lassen können:

root@server:~# openssl ciphers -v

Die SSLCipherSuite-Option EECDH beschränkt die Schlüsselaustauschverfahren auf ephemerale Elliptic Curve Diffie-Hellman-Schlüssel und gewährleistet damit „Perfect Forward Secrecy“ PFS: potentielle Angreifer können mit einem ihnen bekannten Schlüssel einer vorhergehenden Verbindung nicht die zukünftige Kommunikation entschlüsseln. Der Diffie-Hellman-Algorithmus auf der Basis diskreter Logarithmen (Option DHE) ermöglicht ebenfalls PFS, ist aber in bestimmten Konfigurationen anfällig für die in dem Konferenzbeitrag Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice beschriebene Logjam-Attacke. Da er zudem langsamer als die Version mit elliptischen Kurven ist, werden DHE-Verfahren nicht mit aufgelistet.
Die zusätzliche Option !SHA1 schließt den unsicheren Secure Hash-Algorithmus SHA-1 als Hashfunktion für die Integritätssicherung aus.
Durch die Anweisung SSLProtocol TLSv1.2 wird statt der standardmäßig in Apache freigeschalteten Protokolle SSLv3, TLSv1, TLSv1.1 und TLSv1.2 nur noch das TLS-Protokoll in der aktuell sichersten Version 1.2 genutzt.
Die beschriebenen Konfigurationsänderungen orientieren sich an den Empfehlungen der technischen Richtlinie TR-02102-2 zur Verwendung von Transport Layer Security (TLS) des BSI und der RFC 7525: Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS) der Internet Engineering Task Force IETF. Eine detaillierte Beschreibung der SSL-Modul-Konfiguration enthält die Apache-Dokumentation über mod_ssl.

HTTP Strict Transport Security aktivieren

Üblicherweise gibt ein Benutzer im Webbrowser eine Webadresse ohne Angabe des Protokolls ein und ruft sie damit über das nicht-verschlüsselnde „HyperText Transfer Protocol“ HTTP auf. Damit die Datenübertragung trotzdem abgesichert stattfindet, wird in einer typischen Apache-SSL-Konfiguration die Anfrage serverseitig z. B. mit Hilfe der Anweisung Redirect von HTTP auf HTTPS umgeleitet. Die zunächst zum Webserver aufgebaute unverschlüsselte HTTP-Verbindung ist hierbei anfällig für einen Man-in-the-Middle-Angriff. Zusätzlichen Schutz gegen eine solche Attacke bietet das Verfahren „HTTP Strict Transport Security“ HSTS, das eine clientseitige Umleitung im Webbrowser bewirkt.
Zur Einrichtung von HSTS aktivieren wir zunächst mit

root@server:~# a2enmod headers

das Apache-Modul mod_headers und ergänzen dann im VirtualHost-Block der HTTPS-Standardwebsite-Konfigurationsdatei /etc/apache2/sites-available/default-ssl.conf:

<VirtualHost *:443>
  ...
  Header always set Strict-Transport-Security "max-age=31536000"
  ...
</VirtualHost>

Mit der Header-Anweisung wird ein Webbrowser beim ersten Aufruf unserer Website angewiesen, für die durch die Option max-age definierte Zeitspanne von 31536000 Sekunden = ca. 1 Jahr Zugriffe ausschließlich per HTTPS durchzuführen. Hierzu speichert er diese Information zwischen und ersetzt im vorgegebenen Zeitraum automatisch alle HTTP-Aufrufe durch entsprechende HTTPS-Aufrufe. Bei weiteren Besuchen durch denselben Webbrowser wird der Header erneut übertragen und die Information aktualisiert. Da der erste Website-Aufruf unverschlüsselt stattfinden kann, besteht zu diesem Zeitpunkt noch die Gefahr eines Man-in-the-Middle-Angriffs. Daher sollte man für max-age möglichst große Werte wählen.

Sicherheitsmaßnahmen überprüfen

Nach einem Neustart von Apache zur Übernahme unserer Änderungen mit

root@server:~# service apache2 restart

lassen wir den SSL Server Test ein zweites Mal durchlaufen und erhalten folgende Hinweise zu Clients, die keine der vom Server angebotenen Cipher-Suites unterstützen:

...
Handshake Simulation
Android 2.3.7   No SNI 2		Protocol or cipher suite mismatch
Android 4.0.4 	Protocol or cipher suite mismatch
Android 4.1.1 	Protocol or cipher suite mismatch
Android 4.2.2 	Protocol or cipher suite mismatch
Android 4.3 	Protocol or cipher suite mismatch
...
Baidu Jan 2015 	Protocol or cipher suite mismatch
...
IE 6 / XP   No FS 1	  No SNI 2		Protocol or cipher suite mismatch
IE 7 / Vista 	Protocol or cipher suite mismatch
IE 8 / XP   No FS 1	  No SNI 2		Protocol or cipher suite mismatch
IE 8-10 / Win 7  R		Protocol or cipher suite mismatch
...
IE 10 / Win Phone 8.0 	Protocol or cipher suite mismatch
...
Java 6u45   No SNI 2		Protocol or cipher suite mismatch
Java 7u25 	Protocol or cipher suite mismatch
...
OpenSSL 0.9.8y 	Protocol or cipher suite mismatch
...
Safari 5.1.9 / OS X 10.6.8 	Protocol or cipher suite mismatch
...
Safari 6.0.4 / OS X 10.8.4  R		Protocol or cipher suite mismatch
...

Auf den ersten Blick schließt man durch die beschriebenen restriktiven Sicherheitsmaßnahmen relativ viele Clients aus. Im Wesentlichen handelt es sich allerdings um veraltete Versionen von Clientsoftware. Wer auf Kompatibilität zu nicht unterstützten Browser-/Betriebsystem-Kombinationen angewiesen ist, kann natürlich die Apache-Konfiguration entsprechend anpassen. Empfehlenswert ist aber stattdessen ein Update der betroffenen Software auf eine aktuellere und sicherere Version.

Ergänzende Tests mit SecurityHeaders.io durchführen

Neben Strict-Transport-Security für HSTS können weitere sicherheitsrelevante HTTP-Antwortheader zusätzlichen Schutz bieten. Hinweise hierauf erhalten wir mit dem HTTP-Headertest SecurityHeaders.io von Scott Helme:

https://securityheaders.io/?q=https://www.test.local/

Die für unser Testsystem relevanten Auszüge aus den Ergebnissen lauten:

...
Raw Headers
...
Server Apache
...
X-Powered-By PHP/5.5.9-1ubuntu4.14
...
Missing Headers
Content-Security-Policy ...
Public-Key-Pins ...
X-Frame-Options	...
X-XSS-Protection ...
X-Content-Type-Options ...
...

„Security by Obscurity“ einrichten

Die Einträge für Server und X-Powered-By in der Raw Headers-Sektion lassen sich mit „Security by Obscurity“-Maßnahmen optimieren, mit denen Angriffe auf unseren Webserver durch Unterdrücken von Headerinformationen erschwert werden.
Falls man in der Apache-Konfigurationsdatei /etc/apache2/conf-available/security.conf den Eintrag ServerTokens OS bereits in ServerTokens Prod geändert hat, wird im Server-Header nur noch der Name Apache übertragen. Ein vollständiges Löschen des Headers z. B. mit Header always unset Server ist bei der verwendeten Apache-Version 2.4.7 leider nicht möglich.
Die Ausgabe des Headers X-Powered-By können wir hingegen durch Ändern des Eintrags expose_php in der PHP-Konfigurationsdatei /etc/php5/apache2/php.ini komplett unterbinden:

...
;expose_php = On
expose_php = Off
...

Zusätzliche Sicherheitsheader definieren

Fehlende sicherheitstechnisch wichtige Header sind in der Rubrik Missing Headers aufgelistet. Die Wirksamkeit dieser Sicherheitsheader hängt davon ab, ob und wie sie vom verwendeten Browser unterstützt werden.
Wie Strict-Transport-Security definieren wir die zusätzlichen Header Content-Security-Policy, X-Frame-Options, X-Xss-Protection und X-Content-Type-Options in der HTTPS-Standardwebsite-Konfigurationsdatei /etc/apache2/sites-available/default-ssl.conf:

<VirtualHost *:443>
  ...
  Header always set Content-Security-Policy "default-src 'self'"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set X-Xss-Protection "1; mode=block"
  Header always set X-Content-Type-Options "nosniff"
  ...
</VirtualHost>

Zur Aktivierung erfolgt danach noch der obligatorische Neustart von Apache:

root@server:~# service apache2 restart

Der Content-Security-Policy-Header erfordert die meisten Anpassungsarbeiten und wird deshalb zum Schluss behandelt. Die veraltete Alternative X-Content-Security-Policy sollte nicht mehr verwendet werden. Auf das mit der Erweiterung Public Key Pinning Extension for HTTP im Header Public-Key-Pins mögliche „HTTP Public Key Pinning“ HPKP werden wir in einem gesonderten Beitrag eingehen.

X-Frame-Options-Header

Mit X-Frame-Options legen wir fest, unter welchen Voraussetzungen unsere Seiten in andere Websites mit HTML-Anweisungen wie <frame> oder <iframe> eingebettet werden dürfen. Der Parameter SAMEORIGIN lässt dies nur innerhalb unserer eigenen Domain zu. Hiermit verhindern wir das sogenannte „Clickjacking“, bei dem ein Angreifer seine Internetseiten im Browser mit unseren Seiten optisch überlagert. Mausklicks oder Tastatureingaben auf einer scheinbar von uns stammenden Seite könnten dann unerwünschte Aktionen auf der darunterliegenden Seite des Angreifers auslösen. X-Frame-Options wird als Quasistandard von allen führenden Browsern unterstützt.

X-Xss-Protection-Header

Die Browser Internet Explorer, Chrome und Safari enthalten einen nicht standardisierten XSS-Filter, der das sogenannte „Cross-Site-Scripting“ verhindern soll. Beim Cross-Site-Scripting versucht ein Angreifer, ein in der Regel in JavaScript geschriebenes Skript an eine Webseite zu übertragen, die Benutzereingaben z. B. aus Webformularen verarbeitet. Werden die Eingabedaten von der Webanwendung nicht oder nur unzureichend überprüft und an anderer Stelle ungefiltert an den Browser ausgegeben, kann das Skript mit dem eventuellen Schadcode ausgeführt werden.
Der XSS-Filter ist per Voreinstellung aktiviert, kann aber vom Benutzer in den Browseroptionen abgeschaltet werden. Um ihn zu (re)aktivieren, verwenden wir den Header X-Xss-Protection mit dem Wert 1. Durch den zusätzlichen Parameter mode=block wird die Ausgabe einer mit JavaScript „verunreinigten“ Internetseite im Browser unterdrückt und nicht versucht, die Seite vom Skriptcode gereinigt auszugeben.

X-Content-Type-Options-Header

Der Header X-Content-Type-Options mit dem (einzig möglichen) Wert nosniff erzwingt, dass vom Webserver ausgelieferte Dateien stets gemäß dem im zugehörigen Header Content-Type angegebenen Dateityp („MIME-Type“) verarbeitet werden. Er verhindert im Internet Explorer und in Chrome das sogenannte „MIME-Sniffing“, mit dem die Browser versuchen, den korrekten MIME-Type bei fehlenden oder (vermeintlich) falschen Content-Type-Angaben durch Analyse des Dateiinhalts zu ermitteln.
Das eigentlich hilfreiche MIME-Sniffing kann in bestimmten Szenarien eine Sicherheitslücke darstellen. Der Artikel Bypassing Content Security Policy with a JS/GIF Polyglot von Ajin Abraham beschreibt beispielsweise einen Cross-Site-Scripting-Angriff mit Hilfe einer Datei im GIF-Format, die gleichzeitig JavaScript-Code enthält.

Content-Security-Policy-Header

Die „Content Security Policy“ CSP bildet ein Regelwerk, das festlegt, welche Inhalte aus welchen Quellen von einer Webanwendung genutzt werden dürfen. Die Inhalte können dabei Bilder, Skripte, Stylesheets und weitere Objekte sein.
Eine Content Security Policy besteht aus einer Anweisung oder einem Satz von Anweisungen, die durch Semikolons voneinander getrennt sind. Mit der einfachen CSP script-src ’self‘ erlauben wir z. B. die Ausführung von Skripten (script-src) nur aus Dateien, die sich auf unserer (’self‘) Website befinden. Als sinnvoller Grundschutz eignet sich der Content-Security-Policy-Header default-src ’self‘, mit dem wir für alle Objekttypen (default-src) ausschließlich domain-eigene Inhalte zulassen.

Content Security Policy für andere Webanwendungen festlegen

Eine CSP für selbst programmierte Webanwendungen zu definieren, gestaltet sich in der Regel noch recht einfach. Bei Programmen, die man aus anderen Quellen installiert hat, ist häufig eine tiefergehende Analyse erforderlich. Hilfreich sind hierbei Webentwicklungswerkzeuge wie das Firefox-Add-on Firebug. Hiermit können wir eventuell auftretende Fehlermeldungen auswerten und die CSP ausgehend von der Grundeinstellung default-src ’self‘ schrittweise erweitern und modifizieren.
Für die Horde Groupware Webmail Edition, das Datenbank-Administrationswerkzeug phpMyAdmin und das Content-Management-System WordPress wurden auf diese Weise die folgenden CSP ermittelt:

#Horde 5.2.1:
default-src 'self'; img-src 'self' data:; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self'
#phpMyAdmin 4.0.10:
default-src 'self'; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self'; img-src 'self' data:
#WordPress 4.4.2:
default-src 'self'; font-src https://fonts.gstatic.com data:; img-src 'self' https://secure.gravatar.com data:; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self' https://fonts.googleapis.com

Auf eine detaillierte Erläuterung einzelner Anweisungen wird an dieser Stelle verzichtet. Eine ausführliche Beschreibung findet man beispielsweise in der Spezifikation Content Security Policy Level 2 des World Wide Web Consortium W3C.
Zum Schutz vor Cross-Site-Scripting sind bei einer CSP per Voreinstellung Inline-Skripte, also z. B. in HTML eingebetteter JavaScript-Code, deaktiviert. Um den vollen Funktionsumfang nutzen zu können, muss diese Schutzfunktion allerdings bei allen drei aufgeführten Webanwendungen mit der script-src-Option ‚unsafe-inline‘ wieder aufgehoben werden. Hierdurch sind XSS-Attacken durch das Einschleusen von Skripten in manipulierten Benutzereingaben möglich. Um diese Sicherheitslücke zu schließen, müsste der JavaScript-Code konsequent vom HTML-Code getrennt und zusammen mit Eventhandlern wie onClick in eigene Dateien ausgelagert werden.