Einleitung
Auf dem TYPO3camp Stuttgart 2016 hielt Jochen Weiland eine umfassende Session über TYPO3 Security. Dabei zeigte er auch, wie man die Sicherheit seiner TYPO3-Website mit einer einzelnen Zeile TypoScript verbessern kann: es handelte sich um eine Verkettung von HTTP Response Headern unter config.additionalHeaders.
Heute funktioniert das aus zwei Gründen nicht mehr, weshalb ich das alte TypoScript auch nicht zeige:
- config.additionalHeaders wurde bereits in TYPO3 7.6 in ein numerisches Array umgewandelt. Die Verkettung per Pipe-Symbol ist nicht mehr zulässig.
- Es werden regelmäßig neue HTTP Header eingeführt bzw. bestehende Header angepasst.
Inhaltsverzeichnis
- Einrichtung der HTTP Header in TYPO3
- Erläuterung der HTTP Security Header
- HTTP Strict Transport Security (HSTS)
- X-Content-Type-Options
- X-Powered-By
- Referrer Policy
- Permissions-Policy (alter Name: Feature-Policy)
- Content-Security-Policy (CSP)
- Gab es nicht noch mehr Security Header?
- X-Frame-Options
- X-XSS-Protection
- Analyse-Tools für HTTP Header (und mehr)
- Quellen
Einrichtung der HTTP Header in TYPO3
Zunächst findet ihr hier die TypoScript-Konfiguration der aktuell empfohlenen HTTP Security Header.
Bitte kopiere die folgenden Zeilen nicht einfach. Lies weiter, damit du die Mechanismen dahinter verstehst.
config {
additionalHeaders.10.header = Strict-Transport-Security: max-age=31536000; includeSubDomains
additionalHeaders.20.header = X-Content-Type-Options: nosniff
additionalHeaders.30.header = X-Powered-By: nothing
additionalHeaders.40.header = Referrer-Policy: strict-origin-when-cross-origin
# additionalHeaders.50.header = Permissions-Policy: geolocation=(), midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=()
# additionalHeaders.51.header = Feature-Policy: geolocation 'none'; midi 'none'; camera 'none'; usb 'none'; magnetometer 'none'; accelerometer 'none'; vr 'none'; speaker 'none'; ambient-light-sensor 'none'; gyroscope 'none'; microphone 'none'
// Der folgende Header wird später noch unsere gesamte Aufmerksamkeit benötigen:
additionalHeaders.60.header = Content-Security-Policy: frame-ancestors 'self'
}
Die HTTP Header eurer Website könnt ihr unter anderem im Test-Tool https://securityheaders.com prüfen und bewerten lassen. Wenn ihr alle oben genannten additionalHeaders verwendet, habt ihr schon mal eine gute Grundlage geschaffen.
Das Tool belohnt euch derzeit sogar mit der Bestnote A+. Das halte ich allerdings für einen kleinen Fehler: hier wird die vorhandene Content Security Policy eingerechnet, die aber in dieser Form noch keinerlei Schutz vor Cross-Site-Scripting bietet. Dieser letzte Header muss auf jeden Fall noch erweitert werden (dies folgt im zweiten Teil des Tutorials).
Weitere Analyse-Tools findet ihr unten aufgeführt!
Selbstverständlich können HTTP Header nicht nur über TypoScript gesetzt werden.
Verschiedene HTTP Header werden bereits von der mitgelieferten .htaccess-Datei von TYPO3 hinzugefügt. Dazu gehört auch der Security Header X-Content-Type-Options (benötigt das Apache-Modul mod_headers):
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
</IfModule>
Auch direkt über PHP können HTTP Header einfach ergänzt werden:
header('X-Content-Type-Options: nosniff');
Doppelte Header sollten vermieden werden – setzt Header also nicht gleichzeitig über .htaccess und TypoScript.
Erläuterung der HTTP Security Header
Nachfolgend gebe ich einen Überblick über Vorteile und Einrichtung dieser Header. Wenn ein HTTP Header sehr umfangreiche Konfigurationsmöglichkeiten besitzt, beschränke ich mich auf die Beschreibung der grundlegenden Funktionsweise und verweise ansonsten auf dedizierte Beiträge qualifizierterer Menschen. Am Ende dieses Tutorials habe ich weitere Links ergänzt, die ich euch empfehlen kann.
Für alle HTTP Header gilt: die Unterstützung in den verschiedenen Browsern variiert. Einige Browser ignorieren einzelne Header komplett, andere verarbeiten nicht alle Direktiven. Beim Mozilla Developer Network (MDN) findet ihr die Browser-Kompatibilität jedes HTTP Headers.
Bei der Einrichtung von HTTP Headern ist zu beachten:
- Groß- und Kleinschreibung ist beim Header-Namen nicht relevant
- Nach dem Header-Namen folgt ein Doppelpunkt (Ausnahme: Einrichtung in der .htaccess, siehe oben)
- Nach dem Doppelpunkt folgen eine oder mehrere Werte bzw. Direktiven
- Werte bzw. Direktiven werden per Semikolon getrennt
- Falls Direktiven noch Optionen beinhalten, werden diese in einfache Anführungszeichen gesetzt
- Zeilenumbrüche innerhalb eines Headers sind nicht erlaubt
HTTP Strict Transport Security (HSTS)
Dieser Header weist den Browser an, ausschließlich verschlüsselte Verbindungen (HTTPS) zur Website aufzubauen. Dies soll vor einer Downgrade-Attacke schützen.
Voraussetzung ist ein gültiges SSL- bzw. TLS-Zertifikat für die Website. Falls eure Website noch kein Zertifikat besitzt, dürft ihr diesen HTTP Header nicht setzen! Viele Webhoster bieten inzwischen kostenlose Zertifikate mit Let's Encrypt an.
Unter max-age (Zeitangabe in Sekunden) müsst ihr dem Browser mitteilen, für welchen Zeitraum er nur verschlüsselte Verbindungen aufbauen soll. Als Richtwert wird hier meist ein Jahr (31536000 Sekunden) oder gleich zwei Jahre empfohlen. Zu Beginn solltet ihr niedrigere Zeitangaben verwenden, in denen ihr eventuell auftretende Probleme mit eurer Website prüfen könnt.
Eine optionale, aber ebenso empfehlenswerte Direktive ist includeSubDomains, um die Richtlinie auch auf alle Subdomains auszuweiten.
Außerdem gibt es noch die inoffizielle Direktive preload. Falls ihr eure Website in der Preload-Liste von Chrome oder Firefox eintragen lasst und alle Anforderungen erfüllt, werden diese Browser eure Website grundsätzlich per HTTPS aufrufen.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options
Dieser HTTP Header benötigt eine kurze Einleitung: Der Content-Type oder MIME-Type klassifiziert Dateiformate im Internet. Ein Bild mit der Dateiendung .jpg hat den MIME-Type image/jpeg.
Es kann vorkommen, dass einer Datei der MIME-Type fehlt. In diesen Fällen kann der Browser über das sogenannte MIME-Sniffing versuchen, den Dateityp anhand der ersten Bytes der Datei selbst zu ermitteln.
Das MIME-Sniffing kann aber etwa dazu missbraucht werden, Cross-Site-Scripting auszuführen. Der Schadcode wird dabei vom Angreifer in einer Datei versteckt und auf der Website hochgeladen. Der Browser findet mittels MIME-Sniffing den versteckten HTML-Code und führt ihn als solchen aus.
Mit dem Header X-Content-Type-Options könnt ihr das MIME-Sniffing deaktivieren. Der einzig verfügbare Wert ist "nosniff". Alle script-ähnlichen und style-Typen ohne korrekten MIME-Type werden blockiert.
X-Content-Type-Options: nosniff
X-Powered-By
Einige Server-Applikationen setzen diesen Header von sich aus und teilen darüber Informationen über die Serverkonfiguration (z.B. "PHP/5.5.9-1ubuntu4.9"). Für den Aufruf eurer Website ist das vollkommen überflüssig, allerdings nutzen diese Daten ggf. einem Angreifer.
Das komplette Entfernen des HTTP Headers kann je nach Server schwierig werden. Der Wert des Headers lässt sich aber ganz einfach überschreiben. Hier dürft ihr dann auch gerne kreativ werden.
X-Powered-By: Unicorns and kittens
Referrer Policy
Was ist ein Referrer? Wenn ein Browser eine neue Seite aufruft, übermittelt er dabei die Adresse (Referrer) der zuletzt geöffneten Seite (Quelle) mit an die neue Seite (Ziel). So kann die Zielseite ermitteln, woher der Aufruf stammt. Der Referrer wird dabei im HTTP Request Header "Referer" (ja, ist tatsächlich ein Schreibfehler im offiziellen Header-Namen) übermittelt.
Über die Referrer Policy kann man dem Browser mitteilen, unter welchen Umständen welche Informationen an die neue Seite übermittelt werden sollen. Es gibt aktuell acht mögliche Direktiven, die ihr im Detail z.B. bei Scott Helme nachlesen können.
Kurz gesagt, könnt ihr den Referrer auf die Domain reduzieren oder ganz entfernen. Ihr könnt dies etwa davon abhängig machen, ob das Ziel auf eurer eigenen Website oder extern ist, oder ob beim Aufruf ein Downgrade von HTTPS zu HTTP stattfindet.
Mit der Einrichtung der Referrer Policy könnt ihr also den Datenschutz für eure Besucher verbessern, indem ihr Informationen zu besuchten Seiten nicht mit fremden Websites teilt.
Referrer-Policy: strict-origin-when-cross-origin
Am Beispiel von strict-origin-when-cross-origin:
Quelle | Ziel | Referrer |
---|---|---|
https://www.sebkln.de/tutorials/ | https://www.sebkln.de/zur-person/ | https://www.sebkln.de/tutorials/ |
https://www.sebkln.de/tutorials/ | https://demo.sebkln.de/ | https://www.sebkln.de/ |
https://www.sebkln.de/tutorials/ | https://www.example.org/ | https://www.sebkln.de/ |
https://www.sebkln.de/tutorials/ | http://www.sebkln.de/zur-person/ | NULL |
https://www.sebkln.de/tutorials/ | http://www.example.org/ | NULL |
Permissions-Policy (alter Name: Feature-Policy)
Achtung: Dieser Header wurde unter dem Namen "Feature-Policy" entwickelt! Im Mai 2020 erfolgte die Umbenennung in "Permissions Policy". Bei beiden Versionen handelt es sich um einen neuen HTTP Header in einem experimentellen Stadium.
Die vorherige Feature-Policy wird unterstützt von Chrome, Firefox, Edge Chromium und Opera (Stand: 09/2020). Es werden nicht zwingend alle Direktiven unterstützt. Für den Support der neuen Permission-Policy besucht ihr am besten caniuse.com.
Ich empfehle euch, vorerst beide Versionen dieses HTTP Headers zu setzen, bis sich der Browsersupport der Permissions-Policy verbessert hat.
Browser bieten einige Features und APIs, auf die wir Entwickler zugreifen können. Das beinhaltet etwa Kamera und Mikrofon des Endgeräts. Mit einer Permissions Policy können wir diese Funktionen für unsere Seite aktivieren, deaktivieren oder auf eine Quelle begrenzen. Wenn ihr ein Feature abschaltet, können auch keine Dritten darauf zugreifen, etwa per eingebettetem <iframe>. Ihr könnt jedes Feature über eine eigene Direktive individuell einrichten.
Zur Permissions Policy gehören auch Direktiven, mit denen Best Practices auf einer Website erzwungen werden können, etwa die Direktive unoptimized-images. Mit ihr kann man Bilder auf der Website durch Platzhalter ersetzen lassen kann, wenn sie deutlich größer sind als ihr Container. An Smartphone-Nutzern werden dann keine unnötigen Megapixel-Bilder gesendet (besser wäre natürlich die Einrichtung responsiver Bilder, keine Frage). Diese experimentelle Direktive muss aktuell noch vom Nutzer im Browser aktiviert werden.
// Neu seit Mai 2020:
Permissions-Policy: geolocation=(), midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=()
// Vorheriger Name und Syntax:
Feature-Policy: geolocation 'none'; midi 'none'; camera 'none'; usb 'none'; magnetometer 'none'; accelerometer 'none'; vr 'none'; speaker 'none'; ambient-light-sensor 'none'; gyroscope 'none'; microphone 'none'
Ihr findet weitere Beispiele der neuen Syntax für Header-Werte in diesem W3C-Dokument.
Content-Security-Policy (CSP)
Für mich ist dies die stärkste Waffe unter den HTTP Headern. Hiermit kann Cross-Site-Scripting wirkungsvoll unterbunden werden. Die Einrichtung des Headers ist aber aufwendig und erfordert fast immer technische Anpassungen an der Website. Die CSP wird als Whitelist eingerichtet und blockiert alle nicht darin enthaltenen Ressourcen.
Die wichtigsten Direktiven und Fallstricke (gerade im Hinblick auf TYPO3) erläutere ich im zweiten Teil dieses Tutorials: Wie man seine TYPO3-Website (nicht) mit einer Content Security Policy ruiniert.
Als Einstieg bietet sich die folgende Direktive an, die lediglich das Einbetten der eigenen Website in Frames (<frame>, <iframe>, <embed> oder <object>) einschränkt. Auf diesem Wege kann man Clickjacking-Attacken unterbinden.
Content-Security-Policy: frame-ancestors 'self'
Gab es nicht noch mehr Security Header?
Ja, stimmt. Zwei Header waren früher relevant, sind es heute aber nicht mehr:
X-Frame-Options
Bietet die Möglichkeit, das Einbetten der eigenen Website in Frames zu verbieten. Allerdings haben zwei der drei möglichen Direktiven (sameorigin und allow-from) Probleme mit der Evaluierung verschachtelter Frames, wodurch sie als weitgehend nutzlos erachtet werden. Die bessere und aktuellere Alternative ist eine Content Security Policy mit der Direktive frame-ancestors, die für den gleichen Einsatzzweck entwickelt wurde (siehe oben).
Falls du wirklich noch den überalterten Internet Explorer unterstützen musst (der einzige Browser, der die entsprechende CSP-Direktive nicht versteht), könntest du X-Frame-Options: deny verwenden.
X-XSS-Protection
Einige Browser (Chrome, Safari und Internet Explorer/Edge) besitzen einen eingebauten Filter zur Abwehr von Cross-Site-Scripting (XSS). Erkennt der Browser einen XSS-Angriff, wird er entweder den schadhaften Code beim Aufruf entfernen oder den Aufruf der Website abbrechen und stattdessen eine Warnmeldung anzeigen. Mit dem X-XSS-Protection Header könnten wir den Filter für unsere Seite grundsätzlich aktivieren – unabhängig davon ob der Nutzer ihn abgeschaltet hat.
Das Problem hier: die Filter besitzen inzwischen viele Sicherheitslücken und arbeiten nicht mehr zuverlässig. Inzwischen hat Microsoft den Filter im Edge standardmäßig deaktiviert. Google plant seinerseits, seinen XSS Auditor als deprecated zu markieren und ihn zu entfernen.
Mit einer sauber eingerichteten Content Security Policy (CSP) wird der X-XSS-Protection Header überflüssig.
Analyse-Tools für HTTP Header (und mehr)
Die folgenden Services helfen euch bei Prüfung eurer Header. Teilweise werden Header-Direktiven unterschiedlich gewertet.
- https://securityheaders.com (guter Einstieg)
- https://webbkoll.dataskydd.net/de (sehr detailliert aufgeschlüsselt, mit weiteren Hinweisen zu Datenschutz und DSGVO)
- https://observatory.mozilla.org (auf Wunsch mit Third-Party-Scannern zur Prüfung von TLS etc.)
- https://csp-evaluator.withgoogle.com