Signatur
Beschreibung
Das Ereignis securitypolicyviolation wird ausgelöst, sobald der Browser eine Ressource oder Aktion wegen der Content Security Policy (CSP) blockiert oder im Modus Content-Security-Policy-Report-Only nur meldet. Der Handler erhält ein SecurityPolicyViolationEvent mit Angaben dazu, welche Direktive verletzt wurde, welche URI blockiert wurde und an welcher Stelle im Quelltext das passiert ist.
Das Ereignis wird am betroffenen Element ausgelöst (etwa an einem <img> oder <script>), hat bubbles: true und composed: true und steigt deshalb bis zu document und window auf. In der Praxis registriert man den Listener meistens zentral an document, damit alle Verstöße auf der Seite erfasst werden. Verstöße ohne zugehöriges Element (z. B. durch eval() oder fetch()) werden direkt am document bzw. im Worker am globalen Objekt ausgelöst.
Typische Anwendungsfälle sind clientseitiges CSP-Monitoring und -Debugging, das Einsammeln von Verstößen und Weiterleiten an ein eigenes Logging-Backend (ergänzend zu report-uri/report-to) sowie das schrittweise Verschärfen einer Policy im Report-Only-Modus, ohne die Seite kaputtzumachen.
Außer über addEventListener() kann man den Handler auch über die Eigenschaft onsecuritypolicyviolation setzen, die an Elementen, document und window verfügbar ist. Das Ereignis kann nicht abgebrochen werden: Ein preventDefault() hebt die Blockierung nicht auf.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "securitypolicyviolation". |
|
| $handler Pflicht | (event: SecurityPolicyViolationEvent) => void | Callback, das ein SecurityPolicyViolationEvent erhält. Wichtige Eigenschaften: violatedDirective, effectiveDirective, blockedURI, documentURI, originalPolicy, disposition ("enforce" oder "report"), sourceFile, lineNumber, columnNumber, sample, statusCode, referrer. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen wie capture, once, passive oder signal. |
Rückgabewert
addEventListener() gibt undefined zurück. Der Handler bekommt ein SecurityPolicyViolationEvent übergeben.Beispiele
Alle CSP-Verstöße zentral protokollieren
// Seite ausgeliefert mit: Content-Security-Policy: img-src 'self'
document.addEventListener('securitypolicyviolation', (event) => {
console.warn('CSP-Verstoß:', {
direktive: event.effectiveDirective,
blockiert: event.blockedURI,
modus: event.disposition,
ziel: event.target.nodeName
});
});
// Löst einen Verstoß aus, weil externe Bilder nicht erlaubt sind
const img = document.createElement('img');
img.src = 'https://example.com/bild.png';
document.body.append(img);
Verstöße an ein eigenes Monitoring-Backend senden
const reportViolation = (event) => {
const payload = JSON.stringify({
directive: event.effectiveDirective,
blockedURI: event.blockedURI,
documentURI: event.documentURI,
source: `${event.sourceFile}:${event.lineNumber}:${event.columnNumber}`,
sample: event.sample,
disposition: event.disposition
});
// sendBeacon funktioniert auch beim Verlassen der Seite zuverlässig
navigator.sendBeacon('/api/csp-reports', payload);
};
document.addEventListener('securitypolicyviolation', reportViolation);
Handler per on-Property setzen und Listener wieder entfernen
const script = document.createElement('script');
// Variante 1: on-Property direkt am Element
script.onsecuritypolicyviolation = (event) => {
console.log('Skript blockiert:', event.blockedURI);
};
// Variante 2: einmaliger Listener, der danach wieder entfernt wird
const onViolation = (event) => {
console.log('Erster Verstoß:', event.violatedDirective);
document.removeEventListener('securitypolicyviolation', onViolation);
};
document.addEventListener('securitypolicyviolation', onViolation);
script.src = 'https://cdn.fremd.example/lib.js';
document.head.append(script);
Report-Only-Modus zum Testen einer neuen Policy
// Header: Content-Security-Policy-Report-Only: style-src 'self'
const violations = new Map();
document.addEventListener('securitypolicyviolation', (event) => {
if (event.disposition !== 'report') return;
const key = `${event.effectiveDirective} → ${event.blockedURI}`;
violations.set(key, (violations.get(key) ?? 0) + 1);
});
// Nach einer Weile auswerten
setTimeout(() => console.table([...violations]), 5000);
// Wichtig · Fallstricke
- Nicht abbrechbar:
preventDefault()hat keine Wirkung, die blockierte Ressource bleibt blockiert. Das Ereignis dient nur zur Beobachtung. - Listener früh registrieren: Verstöße, die beim Parsen des HTML auftreten, bevor dein Skript läuft, werden nicht mehr erfasst. Den Listener deshalb möglichst früh im
<head>setzen (mit Nonce oder Hash, damit er selbst CSP-konform ist). - Datenschutz/Sicherheit:
blockedURIwird bei fremden Ursprüngen oft auf den Ursprung gekürzt, undsampleenthält höchstens die ersten 40 Zeichen und nur, wenn die Policy'report-sample'enthält. Beim Weitersenden an ein Backend keine sensiblen Daten (Tokens in URLs) ungefiltert speichern. - Kein Ersatz für serverseitiges Reporting: Ein Angreifer mit Skriptzugriff kann clientseitige Listener manipulieren. Für verlässliches Monitoring zusätzlich
report-to/report-uriverwenden. - Ohne Element: Verstöße durch
eval(),new Function(),fetch()oder WebSockets werden amdocumentausgelöst, nicht an einem Element. In Web Workern steht das Ereignis am globalen Worker-Objekt zur Verfügung. - Kompatibilität: Wird von allen modernen Browsern unterstützt; der Internet Explorer unterstützt es nicht. Ältere Browser liefern teils
violatedDirectivestatt der genauereneffectiveDirective-Werte wiescript-src-elem.