#!/coding/blatt
Sammelsurium mit Schwerpunkten Linux & IT-Sicherheit

Permissions-Policy: HTTP-Security-Header zum Schutz vor Feature-Missbrauch

Heutzutage verfügen Webbrowser über diverse Funktionalitäten und Schnittstellen, wie z.B. zum Zugriff auf Kamera, Mikrofon oder Standortdaten des Endgeräts eines Benutzers. In Verbindung mit XSS-Lücken könnten Angreifer, oder eingebundene 3rd-Party-Ressourcen diese Features zweckentfremden bzw. missbrauchen. Zum Schutz davor kann der HTTP-Security-Header Permissions-Policy (ursprünglich Feature-Policy) zum Einsatz kommen. Hiermit lassen sich für eine Website und deren eingebundene Ressourcen einzelne Features explizit sowie gezielt aktivieren, deaktiveren bzw. einschränken.

Näheres zur Permissions-Policy und wie ihr diese auf eurer Website bzw. in eurer Webanwendung einsetzen könnt, erfahrt ihr in diesem Beitrag.

Permissions-Policy - Beschreibung & Funktionsweise

Mit der Permissions-Policy kann dem Webbrowser mitgeteilt werden, welche Origins (Herkunft, die sich zusammengesetzt aus Schema, Hostname und Port) auf welche Features Zugriff haben. Die Policy kann auf Top-Level-Ebene global für die ganze Website als auch einzeln für eingebettete iframe-Elemente definiert werden.

Die Permissions-Policy kann dazu verwendet werden, die Sicherheit als auch die Benutzerfreundlichkeit (Usability) der eigenen Website zu erhöhen. Im Folgenden einige Beispiele, die sich mit der Permissions-Policy umsetzen lassen:

  • Abgreifen von sensiblen Daten verhindern, in dem der Zugriff auf Mikrofon, Kamera, Standort etc. des Benutzers bzw. dessen Endgerät deaktiviert wird.
  • Das automatische Abspielen von Videos, die durch 3rd-Party-Ressourcen eingebunden werden, unterbinden.
  • Die Verwendung von veralteten sowie benutzerunfreundlichen APIs, wie z.B. synchrone XHR-Anfragen, verhindern.

Eine Permissions-Policy setzt sich aus einer oder mehreren Policy-Direktiven zusammen. Eine solche Direktive wiederum besteht aus einem Feature-Namen und einer sogenannten "AllowList". Um dem Webbrowser die zu verwendende Policy mitzuteilen, gibt es zwei Möglichkeiten:

  • per HTTP-Header
  • per allow-Attribut bei iframe-Elementen

Als HTTP-Header innerhalb einer HTTP-Antwort sieht das z.B. wie folgt aus:

HTTP/2 200 OK
date: Sun, 15 Mar 2020 14:30:45 GMT
content-type: text/html; charset=UTF-8
content-length: 2802
permissions-policy: camera=(), microphone=()
HTTP-Antwort mit Permissions-Policy-Header

Das o.a. Beispiel sorgt dafür, dass die aufgerufene Webseite und alle eingebundenen Ressourcen keinen Zugriff auf Kamera und Mikrofon haben. Für alle anderen Features, die nicht spezifiert wurden, gilt weiterhin die Standardeinstellung.

Beispiel - Permissions-Policy in Aktion

An einem einfachen Beispiel soll die Funktionsweise verdeutlich werden. Angenommen ihr ruft eine Webseite mit folgendem Inhalt (nur ein Ausschnitt) auf:

<body>
<div id="myElement">Test</div>
<button type="button" id="doFullScreen">Fullscreen</button>

<script>
    document.getElementById('doFullScreen').addEventListener('click', function() {
        document.getElementById('myElement').requestFullscreen();
    });
</script>
</body>
HTML - Webseite mit Inline-JavaScript für Fullscreen

Ohne Einsatz der Permissions-Policy würde der Webbrowser beim Klick auf den Button das myElement-Element im Vollbildmodus anzeigen. (Es wird vorausgesetzt, dass der Webbrowser einen FullScreen-Modus unterstützt und dieser nicht generell deaktiviert ist.)

Beispiel für Permissions-Policy und Fullscreen

Mithilfe der Permissions-Policy lässt sich das Fullscreen-Feature gezielt deaktivieren. Beim Klick auf den Button würde der Webbrowser den Fullscreen-Modus nicht starten:

Beispiel für Permissions-Policy und Fullscreen

Auf folgenden Websites könnt ihr die Permissions-Policy (Feature-Policy) und die verschiedenen unterstützten Feature-Policy-Direktiven ausprobieren:

Policy-Direktiven im Detail

Da es recht viele Policy-Direktiven gibt, beschränke ich mich im Folgenden auf die gebräuchlichsten Direktiven. Ein Liste aller Direktiven und möglichen Werte findet ihr hier: Permissions-Policy-Direktiven.

Der generelle Aufbau einer Policy-Direktive ist wie folgt: <Feature-Name> <AllowList>.

AllowList-Werte:

*
Feature ist für die Webseite und alle eingebetteten Ressourcen unabhängig der Herkunft (Origin) verwendbar.

self
Feature ist für die Webseite und alle eingebetteten Ressourcen mit der selben Herkunft verwendbar (vgl. Same Origin Policy (SOP)).

'src'(nur für allow-Attribut eines iframe relevant)
Feature ist nur für die eingebundene Webseite und deren eingebundene Ressourcen verwendbar, wenn die Herkunft der des src-Attributs des iframe-Elements entspricht. Für das allow-Attribut ist das der Standardwert für ein spezifiertes Feature ohne explizite "AllowList"-Angabe.

'none'
Feature ist generell deaktiviert und damit weder von der Webseite noch eingebundenen Ressourcen verwendbar.

origin(s)
Feature ist für die Webseite und alle eingebetteten Ressourcen verwendbar, wenn die Herkunft einer der angegebenen Origins (z.B. https://beispiel.de) entspricht. Bei Angabe mehrerer Origins werden diese durch ein Leerzeichen getrennt.

Die Werte * und 'none' können nur alleine angegeben werden. Die anderen können durch Leerzeichen getrennt kombiniert für ein Feature definiert werden.

Jedes von der Permissions-Policy unterstützte Feature hat einen von den folgenden Werten als Standarwert:

  • *
  • self
  • 'none'

Die Standardwerte der einzelnen Features könnt ihr auf folgender Webseite nachschlagen: Permissions-Policy-Direktiven

Feature-Namen: (wie bereits erwähnt nur einige ausgewählte)

camera
Bestimmt, inwieweit der Zugriff auf die Kamera des Benutzers gestattet ist.

geolocation
Bestimmt, inwieweit der Zugriff auf die Standortdaten-API verfügbar ist.

microphone
Bestimmt, inwieweit der Zugriff auf das Mikrofon des Benutzers gestattet ist.

usb
Bestimmt, inwieweit der Zugriff auf die WebUSB-API verfügbar ist.

Eine vollständige Liste aller unterstützten Feature findet ihr hier: unterstützte Features

HTTP-Header vs allow-Attribut eines irame-Elements

Abweichend von der ursprünglichen Feature-Policy hat der HTTP-Header bei der Permissions-Policy immer Vorrang bzw. gibt den Standard vor. Wenn der Zugriff auf die Kamera global per HTTP-Header deaktiviert ist, dann hat eine Aktivierung des Features für ein irame per allow-Attribut keine Auswirkung.
Details hierzu: Header and allow attribute combine differently.

Webbrowser-Unterstützung

Die gängigen Webbrowser unterstützen bereits die doch vergleichsweise noch neue Permissions-Policy. Teilweise muss diese aber auch erst noch explizit in den Webbrowser-Einstellungen aktiviert werden. Zudem muss man sagen, dass ein Großteil der Webbrowser aktuell noch die alte Feature-Policy-Syntax und nicht die neue Permissions-Policy-Syntax unterstützen. Aus diesem Grund ist es ratsam, für eine gewisse Übergangszeit beide HTTP-Header zu senden,

Permissions-Policy übertragen

Um den Webserver anzuweisen, den Feature- bzw. Permissions-Policy-Header zum Client mitzusenden, ist dieser entsprechend zu konfigurieren:

Apache:
In der Konfigurationsdatei von Apache oder in der .htaccess ist folgende Anweisung zu hinterlegen:

Header set Feature-Policy "camera 'none'; microphone self https://beispiel.de; usb *"
Header set Permissions-Policy "camera=(), microphone=(self "https://beispiel.de"), usb=*"
Apache-Konfigurationsdatei bzw. .htacess

nginx:
Analog dazu ist für nginx in der Konfigurationsdatei Folgendes einzufügen:

add_header Feature-Policy "camera 'none'; microphone self https://beispiel.de; usb *";
add_header Permissions-Policy "camera=(), microphone=(self "https://beispiel.de"), usb=*";
nginx-Konfigurationsdatei

Weiterhin kann die Permissions-Policy gezielt für einzelne Frames definiert werden:

<iframe src="https://page2.de" allow="fullscreen"></iframe>
<iframe src="https://page2.de" allow="fullscreen https://page3.de https://page4.de"></iframe>
<iframe src="https://page2.de" allow="fullscreen 'src'; geolocation 'none'"></iframe>
HTML - Permissions-Policy per allow-Attribut für iframe

Permissions-Policy von codingblatt.de

Ich verwende derzeit sowohl den Feature- als auch Permissions-Policy-Header mit folgenden Policy-Direktiven:

  • camera=()
  • geolocation=()
  • gyroscope=()
  • magnetometer
  • microphone=()
  • usb=()

Prinzipiell könnte ich aber auch darauf verzichten, weil ich generell weder 3rd-Party-Ressourcen noch JavaScript in meinem Blog eingebunden habe. Aus "Best-Practice"-Gründen sende ich die Header aber mit.

Weiterführende Informationen

Weiterführende Informationen zum Thema Feature-/Permissions-Policy findet ihr auf folgenden Webseiten:

Fazit

Als Ergänzung zur Content-Security-Policy kann die Permissions-Policy die Sicherheit eurer Website bzw. Webanwendung zusätzlich erhöhen. Nur weil z.B. euer eigener JavaScript-Code Zugriff auf die Kamera haben muss, müsst ihr nicht unbedingt einem 3rd-Party-Skript, welches ihr bspw. über ein CSN eingebunden habt, den Kamerazugriff erlauben.

Zusätzlich kann die Permissions-Policy dazu diesen, eine gute Usability zu gewährleisten. So kann z.B. sichergestellt werden, dass Videos nicht automatisch abgespielt werden, keine veralteten Grafikformate zum Einsatz kommen, keine UI-blockierenden synchronen XHR-Anfragen verwendet werden etc.