Signatur
Beschreibung
Die schreibgeschützte Eigenschaft columnNumber gehört zum Dictionary CSPViolationReport. Dieses Dictionary ist der body eines Berichts vom Typ "csp-violation", den du über einen ReportingObserver im Browser erhältst oder den der Browser per report-to-Direktive an einen Reporting-Endpunkt schickt.
Zusammen mit sourceFile und lineNumber zeigt columnNumber genau, wo im Code die Verletzung ausgelöst wurde. Das kann z. B. ein eval()-Aufruf sein, ein Inline-Handler oder ein dynamisch eingefügtes Skript. Vor allem bei minifiziertem Code, bei dem alles in einer einzigen Zeile steht, ist die Spalte oft die einzige brauchbare Angabe. Mit Source Maps kann man sie auf die ursprüngliche Stelle zurückführen.
Der Wert ist eine Ganzzahl (in der Praxis ab 1 gezählt) oder null, wenn der Browser keine Position ermitteln kann. Das ist etwa der Fall, wenn eine Ressource wie ein Bild oder Stylesheet schon beim Laden blockiert wird und kein Skript die Verletzung ausgelöst hat.
Rückgabewert
lineNumber der Datei sourceFile, an der die Verletzung ausgelöst wurde, oder null, wenn die Position unbekannt ist.Beispiele
CSP-Verletzungen mit ReportingObserver protokollieren
// Voraussetzung: Die Seite wird mit einer CSP ausgeliefert, z. B.
// Content-Security-Policy: script-src 'self'
const observer = new ReportingObserver((reports) => {
for (const report of reports) {
const { sourceFile, lineNumber, columnNumber, effectiveDirective } = report.body;
console.log(`${effectiveDirective} verletzt in ${sourceFile}:${lineNumber}:${columnNumber}`);
}
}, { types: ['csp-violation'], buffered: true });
observer.observe();
// Löst eine Verletzung aus (eval ist ohne 'unsafe-eval' verboten)
try {
eval('1 + 1');
} catch (e) {
console.warn('eval blockiert:', e.message);
}
Fehlende Positionsangaben robust behandeln
const formatLocation = (body) => {
if (!body.sourceFile) return 'unbekannte Quelle';
const line = body.lineNumber ?? '?';
const col = body.columnNumber ?? '?';
return `${body.sourceFile}:${line}:${col}`;
};
const observer = new ReportingObserver((reports) => {
reports.forEach(({ body }) => console.log(formatLocation(body)));
}, { types: ['csp-violation'] });
observer.observe();
Berichte serverseitig empfangen (Node.js/Express)
// Header: Reporting-Endpoints: csp="/csp-reports"
// Content-Security-Policy: script-src 'self'; report-to csp
import express from 'express';
const app = express();
app.use(express.json({ type: ['application/reports+json', 'application/json'] }));
app.post('/csp-reports', (req, res) => {
const reports = Array.isArray(req.body) ? req.body : [req.body];
for (const { type, body } of reports) {
if (type !== 'csp-violation') continue;
console.log('Verletzung:', body.effectiveDirective,
'bei', `${body.sourceFile}:${body.lineNumber}:${body.columnNumber}`);
}
res.sendStatus(204);
});
app.listen(3000);
// Wichtig · Fallstricke
- Kann
nullsein: Prüfe den Wert immer, bevor du ihn weiterverwendest, z. B. mit?? '?'. Wird eine Ressource ohne ausführendes Skript blockiert, gibt es keine Position. - Minifizierter Code: Die Spalte bezieht sich auf die ausgelieferte Datei. Um die Stelle im Original zu finden, brauchst du Source Maps.
- Nicht verwechseln mit dem alten
report-uri-Format: Dort heißt das Feldcolumn-number(mit Bindestrich) und steckt im Objektcsp-report. Überreport-tound denReportingObserverheißt escolumnNumber. - Datenschutz: Bei Skripten von fremden Ursprüngen (Cross-Origin) kann der Browser Positionsangaben weglassen oder kürzen.
- Kompatibilität:
ReportingObserverundreport-towerden vor allem von Chromium-basierten Browsern unterstützt. In anderen Browsern gibt es sie gar nicht oder nur teilweise. Als Alternative bietet sich das Ereignissecuritypolicyviolationan, dessenSecurityPolicyViolationEvent.columnNumberdieselbe Information liefert.