Signatur
Beschreibung
CSPViolationReport ist ein Wörterbuch (Dictionary) der Reporting API, also kein Objekt, das man selbst per Konstruktor erzeugt. Der Browser legt es an, wenn eine Ressource, ein Inline-Skript, ein eval()-Aufruf o. ä. gegen die aktive Content-Security-Policy (oder Content-Security-Policy-Report-Only) verstößt. Der Bericht hat den Typ "csp-violation" und enthält im Feld body ein CSPViolationReportBody mit allen Details zum Verstoß.
Solche Berichte erreichen dich auf zwei Wegen:
- Im Client über einen
ReportingObservermittypes: ["csp-violation"]. Den Report bekommst du dort alsReport-Objekt mit den Eigenschaftentype,urlundbody. - Auf dem Server per HTTP-POST an einen Endpunkt, den du mit dem Header
Reporting-Endpointsfestlegst und in der CSP-Direktivereport-toeinträgst. Der Browser schickt dann ein JSON-Array mit dem Content-Typeapplication/reports+json. Jedes Element darin hat zusätzlich die Felderageunduser_agent.
Typische Anwendungen sind das Einführen einer CSP ohne Risiko: Man verteilt sie zuerst als Report-Only, sammelt die Verstöße und verschärft die Richtlinie danach. Außerdem eignen sich die Berichte, um XSS-Versuche oder unerwartete Drittanbieter-Skripte im Live-Betrieb zu erkennen. Die ältere Direktive report-uri liefert ein anderes JSON-Format (csp-report mit Feldnamen in kebab-case). CSPViolationReport ist das neue, einheitliche Format der Reporting API.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | "csp-violation" | Berichtstyp, bei CSP-Verstößen immer "csp-violation". |
| $url Pflicht | string | URL des Dokuments, in dem der Verstoß aufgetreten ist. | |
| $age | number | Nur im Server-Bericht: Millisekunden zwischen dem Erzeugen und dem Versenden des Berichts. | |
| $user_agent | string | Nur im Server-Bericht: User-Agent-String des meldenden Browsers. | |
| $body.blockedURL | string | Blockierte Ressource oder ein Schlüsselwort wie "inline", "eval", "wasm-eval", "trusted-types-policy". |
|
| $body.documentURL Pflicht | string | URL des Dokuments, dessen Richtlinie verletzt wurde. | |
| $body.effectiveDirective Pflicht | string | Direktive, die tatsächlich gegriffen hat, z. B. "script-src-elem". |
|
| $body.originalPolicy Pflicht | string | Vollständiger Text der verletzten CSP. | |
| $body.disposition Pflicht | "enforce" | "report" | "enforce": Die Ressource wurde blockiert. "report": Der Verstoß wurde nur gemeldet (Report-Only). |
|
| $body.sourceFile | string | null | null | Datei, in der der Verstoß ausgelöst wurde. |
| $body.lineNumber | number | null | null | Zeilennummer in sourceFile. |
| $body.columnNumber | number | null | null | Spaltennummer in sourceFile. |
| $body.sample | string | "" | Die ersten 40 Zeichen des blockierten Inline-Codes. Nur vorhanden, wenn die Direktive 'report-sample' enthält. |
| $body.referrer | string | null | Referrer des Dokuments. | |
| $body.statusCode Pflicht | number | HTTP-Statuscode, mit dem das Dokument ausgeliefert wurde (z. B. 200). |
Rückgabewert
ReportingObserver oder schickt es als JSON an den Reporting-Endpunkt.Beispiele
CSP-Verstöße im Client mit ReportingObserver abfangen
// Seite mit Header: Content-Security-Policy: script-src 'self'
const observer = new ReportingObserver((reports) => {
for (const report of reports) {
const { blockedURL, effectiveDirective, disposition } = report.body;
console.log(`${report.type}: ${blockedURL} verletzt ${effectiveDirective} (${disposition})`);
}
}, { types: ['csp-violation'], buffered: true });
observer.observe();
// Löst einen Verstoß aus: fremdes Skript wird blockiert
const s = document.createElement('script');
s.src = 'https://evil.example/tracker.js';
document.head.append(s);
Reporting-Endpunkt per HTTP-Header einrichten (Node.js/Express)
import express from 'express';
const app = express();
app.use((req, res, next) => {
res.setHeader('Reporting-Endpoints', 'csp-endpoint="https://example.com/csp-reports"');
res.setHeader(
'Content-Security-Policy-Report-Only',
"default-src 'self'; script-src 'self' 'report-sample'; report-to csp-endpoint"
);
next();
});
// Browser sendet ein JSON-Array mit Content-Type application/reports+json
app.post('/csp-reports', express.json({ type: 'application/reports+json' }), (req, res) => {
for (const report of req.body) {
if (report.type !== 'csp-violation') continue;
const { documentURL, blockedURL, effectiveDirective, sample } = report.body;
console.warn('[CSP]', documentURL, '→', blockedURL, effectiveDirective, sample);
}
res.sendStatus(204);
});
app.listen(3000);
Beispiel eines gesendeten CSPViolationReport-JSON
const beispielReport = [{
age: 53531,
type: 'csp-violation',
url: 'https://example.com/seite.html',
user_agent: 'Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0',
body: {
blockedURL: 'inline',
columnNumber: 39,
disposition: 'enforce',
documentURL: 'https://example.com/seite.html',
effectiveDirective: 'script-src-elem',
lineNumber: 121,
originalPolicy: "script-src 'self' 'report-sample'; report-to csp-endpoint",
referrer: 'https://www.google.com/',
sample: 'console.log("lo")',
sourceFile: 'https://example.com/seite.html',
statusCode: 200
}
}];
// Verstöße nach Direktive gruppieren
const proDirektive = Object.groupBy(beispielReport, (r) => r.body.effectiveDirective);
console.log(Object.keys(proDirektive));