Signatur
Beschreibung
Die Eigenschaft originalPolicy des Wörterbuchs CSPViolationReport enthält die komplette Richtlinie als String, genau so, wie sie im Header Content-Security-Policy bzw. Content-Security-Policy-Report-Only oder im <meta http-equiv>-Element übermittelt wurde. Es ist also nicht nur die verletzte Direktive, sondern die gesamte Policy mit allen Direktiven.
Ein CSPViolationReport ist der body eines Berichts vom Typ "csp-violation" der Reporting API. Du bekommst ihn auf zwei Wegen: im Browser über einen ReportingObserver (dann als report.body.originalPolicy) oder auf dem Server als JSON, das der Browser per POST an den Endpunkt aus Reporting-Endpoints schickt, der in der Direktive report-to angegeben ist.
Nützlich ist die Eigenschaft vor allem dann, wenn mehrere Policys parallel gelten, zum Beispiel eine erzwungene und eine im Report-Only-Modus, oder wenn verschiedene Versionen einer Policy ausgerollt werden. Über originalPolicy ordnest du jeden Bericht eindeutig der Policy zu, die ihn ausgelöst hat. Zusammen mit effectiveDirective und disposition siehst du dann, welche Regel in welcher Policy gegriffen hat und ob wirklich blockiert ("enforce") oder nur gemeldet ("report") wurde.
Rückgabewert
"default-src 'self'; img-src 'self' https://cdn.example.com; report-to csp-endpoint". Die Eigenschaft ist schreibgeschützt.Beispiele
Verstöße im Browser mit ReportingObserver auslesen
// Seite ausgeliefert mit:
// Content-Security-Policy: default-src 'self'; img-src 'self'; report-to csp-endpoint
const observer = new ReportingObserver((reports) => {
for (const report of reports) {
const { originalPolicy, effectiveDirective, blockedURL } = report.body;
console.log(`Verstoß gegen "${effectiveDirective}"`);
console.log(`Blockiert: ${blockedURL}`);
console.log(`Policy: ${originalPolicy}`);
}
}, { types: ['csp-violation'], buffered: true });
observer.observe();
// Verstoß provozieren: Bild von fremder Domain laden
const img = new Image();
img.src = 'https://fremd.example.org/bild.png';
document.body.append(img);
Berichte serverseitig (Node.js/Express) nach Policy gruppieren
import express from 'express';
const app = express();
// Der Browser sendet Berichte als application/reports+json
app.use(express.json({ type: ['application/reports+json', 'application/json'] }));
const proPolicy = new Map();
app.post('/csp-reports', (req, res) => {
const reports = Array.isArray(req.body) ? req.body : [req.body];
for (const report of reports) {
if (report.type !== 'csp-violation') continue;
const policy = report.body.originalPolicy;
proPolicy.set(policy, (proPolicy.get(policy) ?? 0) + 1);
}
res.sendStatus(204);
});
app.get('/csp-stats', (req, res) => {
res.json(Object.fromEntries(proPolicy));
});
app.get('/', (req, res) => {
res.set('Reporting-Endpoints', 'csp-endpoint="https://example.com/csp-reports"');
res.set('Content-Security-Policy', "script-src 'self'; report-to csp-endpoint");
res.send('<script src="https://cdn.fremd.org/x.js"></script>');
});
app.listen(3000);
Erzwungene und Report-Only-Policy auseinanderhalten
const ENFORCED = "default-src 'self'";
new ReportingObserver((reports) => {
for (const { body } of reports) {
const quelle = body.originalPolicy.startsWith(ENFORCED) && body.disposition === 'enforce'
? 'Produktiv-Policy'
: 'Test-Policy (Report-Only)';
console.log(`${quelle}: ${body.effectiveDirective} → ${body.blockedURL}`);
}
}, { types: ['csp-violation'] }).observe();
// Wichtig · Fallstricke
- Altes Format: Beim veralteten
report-urischickt der Browser ein anderes JSON (Content-Type: application/csp-report). Das Feld heißt dort"original-policy"in Kebab-Case und steckt im Objekt"csp-report". Ein Server, der beide Formate annimmt, muss beide Schreibweisen auswerten. - Browser-Unterstützung:
report-tomitReporting-EndpointsundReportingObserverfür CSP funktionieren zuverlässig nur in Chromium-Browsern. Für Firefox und Safari solltest du zusätzlichreport-uriangeben oder das Eventsecuritypolicyviolationnutzen. - Größe und Datenschutz: Die Policy kann lang sein und bei jedem Bericht erneut übertragen werden. Speichere sie serverseitig am besten gehasht oder normalisiert, statt sie in jedem Protokolleintrag zu wiederholen. Nonces in der Policy (
'nonce-…') wechseln bei jeder Anfrage. Ersetze sie vor dem Gruppieren durch einen Platzhalter, sonst bekommst du für jede Anfrage eine eigene Gruppe. - Berichte sind vom Client kontrollierbare Eingaben. Validiere sie auf dem Server und gib
originalPolicyin Admin-Oberflächen nie ungefiltert als HTML aus (XSS-Gefahr). - Berichte werden gebündelt und zeitverzögert zugestellt. Erwarte also keine Echtzeit.