Signatur
Beschreibung
PermissionsPolicyViolationReport ist ein Wörterbuch (Dictionary) der Reporting API. Es beschreibt einen Verstoß gegen die Permissions Policy eines Dokuments, also gegen die Regeln, die über den HTTP-Header Permissions-Policy oder das allow-Attribut eines <iframe> festlegen, welche Browser-Funktionen (Kamera, Mikrofon, Geolocation, Fullscreen, Zahlungs-API usw.) ein Dokument nutzen darf.
Man erhält solche Berichte auf zwei Wegen:
- Clientseitig über einen
ReportingObserver, der mittypes: ["permissions-policy-violation"]konfiguriert ist. - Serverseitig: Der Browser schickt die Berichte als JSON per POST an einen Endpunkt, der mit dem Header
Reporting-Endpointsdefiniert und in der Policy perreport-to=…referenziert wird.
Ein Bericht hat die Eigenschaften type (immer "permissions-policy-violation"), url (URL des betroffenen Dokuments) und body. Der body enthält featureId (z. B. "geolocation"), sourceFile, lineNumber und columnNumber (Stelle des auslösenden Codes, sofern bekannt) sowie disposition: "enforce", wenn die Funktion tatsächlich blockiert wurde, oder "report", wenn die Policy nur im Beobachtungsmodus (Permissions-Policy-Report-Only) läuft.
Einsatzzweck: Beim Einführen oder Verschärfen einer Permissions Policy zeigt die Auswertung solcher Berichte, welcher eigene Code oder welche Drittanbieter-Skripte gesperrte Funktionen verwenden wollen, bevor die Einschränkung Nutzer merklich trifft.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | "permissions-policy-violation" | Berichtstyp; bei diesem Bericht immer "permissions-policy-violation". |
| $url Pflicht | string | URL des Dokuments, in dem der Verstoß aufgetreten ist. | |
| $body.featureId Pflicht | string | Name der betroffenen Funktion der Policy, z. B. "geolocation", "camera", "fullscreen". |
|
| $body.sourceFile | string | null | null | URL des Skripts, das den Verstoß ausgelöst hat, falls bekannt. |
| $body.lineNumber | number | null | null | Zeilennummer im sourceFile, falls bekannt. |
| $body.columnNumber | number | null | null | Spaltennummer im sourceFile, falls bekannt. |
| $body.disposition Pflicht | "enforce" | "report" | "enforce": Die Funktion wurde blockiert. "report": Der Verstoß wurde nur gemeldet (Report-Only-Modus). |
Rückgabewert
ReportingObserver im Array reports übergeben oder vom Browser als JSON an den konfigurierten Endpunkt gesendet.Beispiele
Verstöße clientseitig mit ReportingObserver erfassen
// Server sendet z. B.: Permissions-Policy: geolocation=()
const observer = new ReportingObserver((reports) => {
for (const report of reports) {
const { featureId, disposition, sourceFile, lineNumber } = report.body;
console.warn(
`Policy-Verstoß: ${featureId} (${disposition}) in ${sourceFile}:${lineNumber}`
);
}
}, { types: ['permissions-policy-violation'], buffered: true });
observer.observe();
// Löst den Verstoß aus, weil Geolocation per Policy gesperrt ist
navigator.geolocation.getCurrentPosition(
() => {},
(err) => console.log('Fehler:', err.message)
);
Berichte gebündelt an eigenes Monitoring senden
const observer = new ReportingObserver((reports) => {
const payload = reports.map((r) => ({
page: r.url,
feature: r.body.featureId,
disposition: r.body.disposition,
source: r.body.sourceFile,
line: r.body.lineNumber,
column: r.body.columnNumber
}));
navigator.sendBeacon('/api/policy-reports', JSON.stringify(payload));
}, { types: ['permissions-policy-violation'] });
observer.observe();
// Beim Verlassen der Seite noch ausstehende Berichte abholen
addEventListener('pagehide', () => {
const pending = observer.takeRecords();
if (pending.length) {
navigator.sendBeacon('/api/policy-reports', JSON.stringify(pending));
}
});
Serverseitiger Report-Endpunkt mit Node.js/Express (Report-Only)
import express from 'express';
const app = express();
app.use((req, res, next) => {
res.set('Reporting-Endpoints', 'policy="https://example.com/reports"');
// Nur beobachten, nicht blockieren -> disposition: "report"
res.set('Permissions-Policy-Report-Only', 'camera=(), microphone=();report-to=policy');
next();
});
app.post('/reports', express.json({ type: 'application/reports+json' }), (req, res) => {
for (const report of req.body) {
if (report.type === 'permissions-policy-violation') {
console.log(report.body.featureId, report.body.disposition, report.url);
}
}
res.sendStatus(204);
});
app.listen(3000);
// Wichtig · Fallstricke
- Kompatibilität: Experimentell und bisher nur in Chromium-Browsern umgesetzt. Firefox und Safari erzeugen keine solchen Berichte. Vor der Nutzung mit
'ReportingObserver' in windowprüfen und nicht davon ausgehen, dass Berichte zuverlässig ankommen. PermissionsPolicyViolationReportist ein Dictionary und keine Klasse. Es gibt also keinen Konstruktor, undinstanceoffunktioniert nicht. Unterscheide Berichte stattdessen überreport.type.sourceFile,lineNumberundcolumnNumberkönnennullsein, etwa bei Verstößen durch dasallow-Attribut eines iframes oder bei Skripten anderer Herkunft.- Nicht jeder Zugriff auf eine gesperrte Funktion erzeugt einen Bericht. Welche Funktionen Berichte auslösen, hängt vom Browser ab.
- Serverseitig kommen die Berichte gebündelt und verzögert mit dem MIME-Typ
application/reports+json. Der Endpunkt muss HTTPS nutzen und bei fremder Herkunft CORS erlauben. Berichte enthalten URLs und sind deshalb vor dem Speichern auf personenbezogene Daten (Query-Parameter) zu prüfen. - Die ältere Header-Form
Report-Toist veraltet. VerwendeReporting-Endpoints.