Tastaturlayout Ausschnitt

Content Security Policy

Content Security Policy

Content Security Policy (CSP) ist der HTTP-Header, der eine feine Steuerung für alle im Rahmen einer Website zu ladenden Ressourcen ermöglicht. Ich kann für alle Ressourcen-Typen festlegen, von welchen Quellen und z.T. auch, in welchem Verfahren sie geladen werden dürfen.

Die korrekte und umfassende Implementation dieses Headers kann im besten Fall nahezu alle XSS-Anfälligkeiten von Webressourcen verhindern und entsprechende Attacken abwehren.

Jetzt könnte man fragen, ob man solch neumodischen Kram wirklich braucht, man hat doch bloß ein einfaches Blog, und das schon seit Jahren…

Kann man, aber zu bedenken ist dabei, dass CSP eine Entwicklung des Mozilla Project ist und aus dem Jahr 2009 stammt. Zur Zeit ist Level 3 beim W3C in Diskussion und vor der Verabschiedung als RFC. Die Sache ist also schon alt und wurde lange schlicht vernachlässigt.

Nun zur Anwendung…

Allerdings, vgl. den o.a. Link, ist dieses Projekt praktisch nur auf neuen Websites, die man selbst entwickelt hat, und zwar schon im Zuge dieser Entwicklung, einfach und problemlos zu implementieren. Bei einem schon bestehenden WordPress-Blog zum Beispiel stellt sich das Unternehmen als höchst anspruchsvoll dar. Man benötigt viel sorgfältige Überlegung, um für sämtliche Ressourcen, die das Blog ausliefern kann, zu ermitteln, woher und auf welche Weise sie eigentlich zu Anzeige kommen.

Die WordPress-Downside

Tatsächlich – und bedauerlicherweise – dürfte es gar nicht gelingen, einem halbwegs modernen WordPress-Blog eine vollständige CSP zu verabreichen, die ihrer Aufgabe wirklich gerecht werden kann.

Das liegt schlicht daran, dass WordPress mindestens im Adminbereich, aber auch in zahlreichen Frontend-Themes Inline-Javascripte und Inline-Styles einsetzt!

Inline-Javascripte sind eigentlich seit ca. 1995 (also unmittelbar nach der Erfindung von Javascript), Inline-Styles seit ca. Ende 1996 (CSS Level 1) in der Anwendung VERBOTEN.

Beides steht im Wesentlichen für Faulheit, Pfusch und Nichtwissen, wie man es richtig macht! Schade, sind doch Inline-Elemente so einfach auch noch nachträglich in eine bestehende Struktur einzubinden. Sie ersparen dem Entwickler viel Arbeit. Aber sie ersparen auch dem kriminellen Verbreiter von Schadcode viel Arbeit, weil man dank ihnen so einfach Schadcode in eine gerade aufgerufene Seite »einfließen lassen« kann…

In WordPress-Kreisen wird die Problematik diskutiert, In den WP-Foren gibt es zahlreiche Threads dazu, eine wirklich befriedigende Lösung gibt es wohl zur Zeit nicht. Erforderlich wäre größeres Umarbeiten von Kern-Code, um alle Javaskripte (die z.T. sozusagen on the fly mittel PHP-Code in den Quelltext eingefügt werden, genau wie Inline-Styles) in statische Skript-Dateien auszulagern.

Aber Ok, wir WP-Blogger haben jetzt erst einmal die Malaise, also schauen wir mal, was wir in Sachen CSP trotzdem draus machen können.

Der CSP-Header

Der Header funktioniert im Prinzip wie die anderen schon genannten Direktiven auch:

<IfModule mod_headers.c>
  Header set X-Frame-Options "deny"
  Header set X-Content-Type-Options "nosniff"
  Header set X-XSS-Protection "1; mode=block"
  Header set Referrer-Policy "no-referrer"
  Header set Strict-Transport-Security: "max-age=63072000
  Header set Content-Security-Policy "parameter 'wert'; parameter 'wert'; ...
</IfModule>

#BEGIN WordPress
...
...

Jetzt gilt es, für alle Ressourcen, die auf den Seiten einer Website von Servern geladen und an den aufrufenden Webbrowser ausgeliefert werden, festzulegen, von welchen Quellen genau sie geladen werden dürfen.

Ein Beispielfall mag eine ganz einfach aufgebaute Website sein, die lediglich aus HTML und einem eingebundenen Stylesheet besteht und als Inhalte bloß Text und eigene Fotos und womöglich auch Fotos aus einer bestimmten Bilderquelle präsentiert.

Der CSP-Header könnte dann ganz schlicht so aussehen:

Header set Content-Security-Policy "default-src 'self'; img-src 'self' https://bilderquelle.dom; object-src 'none'"

Das bedeutet, dass Inhalte generell nur von der eigenen Domain stammen dürfen mit Ausnahme von Bildern, die auch von der genannten Fremdquelle stammen dürfen. Darüberhinaus dürfen keine Ressourcen wie Plugins geladen werden. Inline-Skripte und Inline-Styles sind ebenfalls untersagt, da sie nicht ausdrücklich erlaubt werden.

Im Falle unserer WordPress-Blogs ist die Sache erheblich aufwändiger, denn wir müssen erst einmal ermitteln, woher unsere Blog-Maschinerie überhaupt Bilder, Skripte, Styles, Fonts und was noch alles bezieht.

Sinnvoll in diesem Zusammenhang ist sicher die Verwendung der Webentwickler-Tools, wie sie die meisten modernen Webbrowser anbieten. Damit kann man in der Regel recht übersichtlich die Ressourcen auflisten lassen, von denen unser Blog (und auf den diversen Subseiten… und im Admin-Bereich!) seine Ressourcen bezieht. Man kann hier auch recht zuverlässig ermitteln, ob und wo unser Blog-Theme (Admin-Bereich nicht vergessen!) Inline-Skripte und Inline-Styles einsetzt.

Ich kann schon vorausschicken, dass auch nur das kleinste <script>Skriptanweisung Blabla…</script> oder <span style=Styleanweisung> Blabla…</span> oder gar so etwas wie onclick= oder onmouseover= dafür sorgt, dass man diese Untugenden in der CSP ausdrücklich erlauben muss, was einem eine Spitzenbewertung in Sachen Content Security bei den diversen Analyseseiten (siehe Links am Anfang) geradewegs gründlich vermasselt.

Schauen wir trotzdem weiter, was wir tun können. Ich nehme mein Blog einfach einmal als Beispiel.

CSP konkret in meinem Blog

Ich habe nach einigem Ausprobieren folgenden CSP-Header zusammengestellt, der zur Zeit tatsächlich funktioniert:

Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; connect-src 'self'; child-src 'self'"

Sehr hilfreich beim Zusammenstellen der Direktive waren mir die ausführlichen Erläuertungen von Scott Helme, Thorsten H. Willert, aber auch die schon angegebenen Mozilla-Ressourcen und Übersichten.

Es ist wirklich eine Sache des Ausprobierens, und vieles hängt auch davon ab, welches WordPress-Theme man verwendet, welche Plugins man einsetzt und welche Codeschnipsel man eventuell sogar selbst in eine functions.php eingefügt hat.

Im Zusammenhang mit den anderen besprochenen Security Headern sieht der gesamte Block dann so aus:

<IfModule mod_headers.c>
  Header set X-Frame-Options "deny"
  Header set X-Content-Type-Options "nosniff"
  Header set X-XSS-Protection "1; mode=block"
  Header set Referrer-Policy "no-referrer"
  Header set Strict-Transport-Security: "max-age=63072000
  Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; connect-src 'self'; child-src 'self'"
</IfModule>

#BEGIN WordPress
...
...

Ich betrachte es als eine Art sportlichen Wettkampf – bei allem Ernst der Sache, eine funktionierende Content Security Policy in meinem Blog zu realisieren und damit ein halbwegs passables Sicherheitslevel zu erreichen.

Die ideelle Belohnung für die erhebliche Mühe sind für mich die einigermaßen guten Bewertungen, die ich dann auf den zu Beginn angeführten Testsuiten erzielen kann. Hier nochmal zusammengefasst:

Einen Punkt muss ich noch nachtragen, wir können die .htaccess-Datei unserer Website noch ein Stückchen optimieren hinsichtlich konsequenter Umsetzung von Sicherheitsrichtlinien. Dies betrifft noch einmal den Einsatz des HSTS-Headers, den ich an früherer Stelle besprochen habe. …bitte umblättern

HSTS – Eine wichtige Ergänzung

Zur Erinnerung: HSTS stellt die Anforderung an Strict Transport Security dar, die mittels HTTPS-Protokoll erreicht wird. Ergänzt werden sollte in der .htaccess der folgende Umschrift- bzw. Umleitungs-Block (vor dem soeben gebastelten Header-Block):

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L,E=HTTPS:1]

Die Rewrite-Regeln sorgen dafür, dass Aufrufe von Seiten der eigenen Website, die per HTTP erfolgen, automatisch umgeschrieben werden in HTTPS-Aufrufe (und damit eine transportverschlüsselte Auslieferung veranlasst wird).

Also Aufrufe von z.B. http://www.meineadresse.de und http://meineadresse.de werden auf https://www.meineadresse.de bzw. https://meineadresse.de umgeschrieben.

Ein solcher Rewrite-Block ist im Übrigen obligatorisch, wenn man seine Website in die HSTS Preload List aufnehmen lassen will.

Finally! Ein Schlusswort.

Ich bin am Ende angekommen und es war ein ganz schöner Brocken Inhalt. Er reflektiert meine persönliche Beschäftigung mit der Sicherheit meines Blogs in den letzten Wochen. Das ging einher mit meiner Einarbeitung in das aktuelle WordPress 5.9, das neue Theme »Twenty Twenty-Two» und Full Size Editing mit dem Block Editor (Gutenberg).

Das ist und war zugegebenermaßen viel Arbeit und gehöriger Lernaufwand, aber mir hat das Spaß gemacht. Für mich war es, seit ich Webseiten entwickelt habe (was ich heute eigentlich längst nicht mehr tue), immer eine Herausforderung, es so gut wie möglich zu machen. Und spätestens heute sind nun einmal Fragen der Sicherheit wichtig geworden. Das Web hat seine Unschuld lange verloren (es ist durch und durch kommerziell geworden) und da draußen treiben sich Legionen von Schadcode verbreitenden Bots und Skripten herum, bereit, jede sich auftuende Anfälligkeit und Sicherheitslücken nach Kräften auszunutzen.

Es gibt noch einige weitere Security-Header, die man einsetzen kann, die ich aber selbst nicht verwende und hier auch nicht erwähne. Die angegebenen Quellen bieten aber auch hierfür Erläuterungen und Einsatzmöglichkeiten.

Bleibt noch zu erwähnen, dass ich die Thematik in diesem Artikel nur anreißen konnte. Die a.a.O. verlinkten Quellen bieten Anknüpfungspunkte genug, sich tiefer in die Materie einzuarbeiten – wenn man denn will. Es steht jedem frei, sich um Sicherheitsbelange zu kümmern oder eben nicht. Es gibt sicher kein Verfahren, zu ermitteln, »ob es sich lohnt«. Das Ausbleiben von erfolgreichen Angriffen kann an den eingesetzten Maßnahmen liegen, es kann aber auch nur ein Fall von »bisher Glück gehabt« sein.

Mich interessiert die gesamte Thematik, ich hatte Lust, mich einzuarbeiten, wie ich überhaupt auch in fortgeschrittenem Alter immer noch Lust auf Lernen habe. In diesem Sinne hat sich die Unternehmung Content Security Policy – und weitere »Security Header« für mich schon jetzt gelohnt.

Glückwunsch und Dank geht natürlich an alle von euch, die diesen raumgreifenden Beitrag bis hierhin – zum Schluss – gelesen haben!

Nachtrag 24.02.2022

Es gibt eine ganze Reihe von WordPress-Plugins, die antreten, die besprochenen Aufgaben komfortabel und interaktiv im Adminbereich des Blogsystems zu lösen. Wer die manuelle Mühe scheut oder Bedenken hat, dabei Fehler zu machen und sein Blog zumindest kurzfristig »abzuschießen«, sollte sich dort einmal umschauen. Möglicherweise findet sich eine Lösung, die tauglich ist, die besprochenen Sicherheitsdirektiven interaktiv zusammenzustellen, so dass sie im jeweiligen Blog funktionieren. Ich kann das nicht beurteilen, da ich keines der Plugins ausprobiert habe.

Seiten: 1 2