Signatur
Beschreibung
Das Ereignis securitypolicyviolation wird am WorkerGlobalScope (also an self in einem Dedicated, Shared oder Service Worker) ausgelöst, wenn eine Aktion im Worker gegen die für ihn gültige Content Security Policy verstößt. Typische Auslöser sind blockierte Netzwerkanfragen (connect-src), per importScripts() geladene Skripte (script-src/worker-src) oder eval() ohne 'unsafe-eval'.
Der Handler erhält ein SecurityPolicyViolationEvent mit Details wie blockedURI, violatedDirective, effectiveDirective, originalPolicy, disposition ("enforce" oder "report"), sourceFile, lineNumber und columnNumber. Damit lassen sich CSP-Verstöße clientseitig protokollieren, an einen eigenen Endpunkt melden oder im Entwicklungsbetrieb schnell diagnostizieren.
Registrierung erfolgt entweder über self.addEventListener("securitypolicyviolation", handler) oder über die Eigenschaft self.onsecuritypolicyviolation = handler. Das Ereignis ist nicht abbrechbar; es informiert lediglich – die Blockierung selbst ist bereits erfolgt (bzw. im Modus Content-Security-Policy-Report-Only nur gemeldet).
Welche CSP für einen Worker gilt, hängt von seiner Herkunft ab: Worker aus eigenen Skript-URLs erhalten die CSP aus den HTTP-Headern der Worker-Skript-Antwort; Worker aus blob:- oder data:-URLs erben in der Regel die Richtlinie des erzeugenden Dokuments.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "securitypolicyviolation". |
|
| $handler Pflicht | (event: SecurityPolicyViolationEvent) => void | Callback, der mit einem SecurityPolicyViolationEvent aufgerufen wird. Alternativ als self.onsecuritypolicyviolation zuweisbar. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen wie once oder signal (zum Entfernen per AbortController). |
Rückgabewert
addEventListener() gibt nichts zurück. Der Handler erhält ein SecurityPolicyViolationEvent.Beispiele
CSP-Verstöße im Worker per addEventListener protokollieren
// worker.js – ausgeliefert mit Header:
// Content-Security-Policy: connect-src 'self'
self.addEventListener('securitypolicyviolation', (event) => {
console.warn('CSP-Verstoß im Worker:', {
blockiert: event.blockedURI,
direktive: event.effectiveDirective,
modus: event.disposition
});
});
// Diese Anfrage verstößt gegen connect-src 'self'
fetch('https://api.fremd.example/daten').catch((err) => {
console.error('fetch fehlgeschlagen:', err.message);
});
Verstöße an den Haupt-Thread melden (on-Property)
// worker.js
self.onsecuritypolicyviolation = (event) => {
self.postMessage({
typ: 'csp-violation',
blockedURI: event.blockedURI,
directive: event.violatedDirective,
source: `${event.sourceFile}:${event.lineNumber}`
});
};
try {
importScripts('https://cdn.unerlaubt.example/lib.js');
} catch (e) {
self.postMessage({ typ: 'fehler', text: e.name });
}
// main.js
const worker = new Worker('worker.js');
worker.addEventListener('message', ({ data }) => {
if (data.typ === 'csp-violation') {
console.log('Worker meldet CSP-Verstoß:', data.directive, data.blockedURI);
}
});
Verstöße gebündelt an eigenen Endpunkt senden und Listener entfernen
// worker.js
const controller = new AbortController();
const puffer = [];
const onViolation = (event) => {
puffer.push({
blockedURI: event.blockedURI,
directive: event.effectiveDirective,
sample: event.sample,
zeit: Date.now()
});
};
self.addEventListener('securitypolicyviolation', onViolation, {
signal: controller.signal
});
// Alle 10 Sekunden senden
const intervall = setInterval(async () => {
if (puffer.length === 0) return;
const batch = puffer.splice(0);
await fetch('/csp-report', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batch)
});
}, 10_000);
// Beim Herunterfahren aufräumen
self.addEventListener('message', ({ data }) => {
if (data === 'stop') {
controller.abort(); // entspricht removeEventListener
clearInterval(intervall);
self.close();
}
});
// Wichtig · Fallstricke
- Endlosschleife vermeiden: Wird der Report selbst per
fetch()an einen Endpunkt gesendet, der ebenfalls gegenconnect-srcverstößt, löst das erneut das Ereignis aus. Den Report-Endpunkt daher immer erlauben (z. B.'self'). - Nicht abbrechbar:
preventDefault()hat keine Wirkung; die Ressource bleibt blockiert. - Welche CSP gilt? Worker aus regulären URLs nutzen die CSP-Header der Worker-Skript-Antwort, nicht die des Dokuments.
blob:-/data:-Worker erben die Richtlinie des Erzeugers. Das führt häufig zu Verwirrung, wenn Verstöße „nicht auftauchen“. - Datenschutz/Sicherheit:
blockedURIwird bei Cross-Origin-Weiterleitungen teils auf den Ursprung gekürzt;sampleist nur gefüllt, wenn die Richtlinie'report-sample'enthält. Gemeldete Daten nicht ungeprüft in HTML einsetzen (XSS). - Report-Only: Bei
Content-Security-Policy-Report-Onlywird das Ereignis mitdisposition === "report"ausgelöst, ohne dass etwas blockiert wird – ideal zum Testen neuer Richtlinien. - Kompatibilität: In aktuellen Chromium-, Firefox- und Safari-Versionen unterstützt; ältere Browser feuern das Ereignis nur am
Document, nicht im Worker. Als Ergänzung bietet sich die serverseitigereport-to-Direktive bzw. die Reporting API (ReportingObserver) an.