Start · Sprachen · JavaScript · Referenz · CSPViolationReport.lineNumber

CSPViolationReport.lineNumber

Eigenschaft

Gibt die Zeilennummer (ab 1) in der Quelldatei an, in der der CSP-Verstoß ausgelöst wurde, oder <code>null</code>, wenn sie unbekannt ist.

seit JavaScript Reporting API: Chromium-Browser (Chrome/Edge 69+ f Kategorie: webapi

Signatur

CSPViolationReport.lineNumber

Beschreibung

Die Eigenschaft lineNumber gehört zum Dictionary CSPViolationReport. Das ist der Inhalt (body) eines Berichts vom Typ "csp-violation" aus der Reporting API. Sie enthält die Zeilennummer in der Datei aus sourceFile, an der die Content Security Policy verletzt wurde, zum Beispiel durch einen blockierten eval()-Aufruf, ein blockiertes Inline-Skript oder das Laden einer nicht erlaubten Ressource.

Zusammen mit sourceFile und columnNumber zeigt lineNumber genau auf die Codestelle, die den Verstoß verursacht hat. Das ist besonders hilfreich, wenn man eine strenge CSP zuerst im Modus Content-Security-Policy-Report-Only einführt und alle problematischen Stellen finden möchte, bevor die Richtlinie tatsächlich etwas blockiert.

Man stößt auf den Wert an zwei Stellen:

  • Im Client über einen ReportingObserver mit types: ["csp-violation"]. Dann ist er als report.body.lineNumber erreichbar.
  • Auf dem Server im JSON-Bericht, den der Browser an den Endpunkt aus der Direktive report-to (definiert per Reporting-Endpoints-Header) schickt. Dort steht er im Feld body.lineNumber.

Die Eigenschaft ist schreibgeschützt und hat einen Wert von 1 aufwärts. Wenn der Browser keine Codestelle zuordnen kann, zum Beispiel bei Verstößen durch HTML-Attribute oder beim Laden von Ressourcen ohne Skriptkontext, ist der Wert null oder 0.

Rückgabewert

Typ
number | null
Beschreibung
Zeilennummer (ab 1) in sourceFile, an der der Verstoß ausgelöst wurde. Ist keine Zuordnung möglich, ist der Wert null oder 0.

Beispiele

CSP-Verstöße im Client mit ReportingObserver protokollieren

// Voraussetzung: Seite liefert z. B. den Header
// Content-Security-Policy: script-src 'self'
const observer = new ReportingObserver((reports) => {
  for (const { type, body } of reports) {
    if (type !== 'csp-violation') continue;
    const ort = body.lineNumber
      ? `${body.sourceFile}:${body.lineNumber}:${body.columnNumber ?? 0}`
      : '(keine Codestelle bekannt)';
    console.warn(`CSP-Verstoß gegen ${body.effectiveDirective} bei ${ort}`);
  }
}, { types: ['csp-violation'], buffered: true });

observer.observe();

// Löst einen Verstoß aus, falls 'unsafe-eval' nicht erlaubt ist
try { eval('1 + 1'); } catch (e) { /* EvalError durch CSP */ }
CSP-Verstoß gegen script-src bei https://example.com/app.js:14:3

Berichte am Server-Endpunkt auswerten (Node.js/Express)

// Response-Header der Seite:
// Reporting-Endpoints: csp="https://example.com/csp-reports"
// Content-Security-Policy-Report-Only: 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 report of reports) {
    if (report.type !== 'csp-violation') continue;
    const { sourceFile, lineNumber, columnNumber, blockedURL } = report.body;
    console.log(`Blockiert: ${blockedURL} – ${sourceFile ?? '?'}:${lineNumber ?? '?'}:${columnNumber ?? '?'}`);
  }
  res.sendStatus(204);
});

app.listen(3000);
Blockiert: inline – https://example.com/index.html:27:5

Verstöße nach Codestelle gruppieren

// Fasst gleiche Verstöße zusammen, damit sie sich leichter aufräumen lassen
const gruppiereNachStelle = (bodies) => {
  const zaehler = new Map();
  for (const b of bodies) {
    const key = `${b.sourceFile ?? 'unbekannt'}:${b.lineNumber ?? '-'}`;
    zaehler.set(key, (zaehler.get(key) ?? 0) + 1);
  }
  return Object.fromEntries(zaehler);
};

const bodies = [
  { sourceFile: 'https://example.com/app.js', lineNumber: 14 },
  { sourceFile: 'https://example.com/app.js', lineNumber: 14 },
  { sourceFile: null, lineNumber: null }
];

console.log(gruppiereNachStelle(bodies));
{ 'https://example.com/app.js:14': 2, 'unbekannt:-': 1 }

// Wichtig · Fallstricke

  • Browser-Unterstützung: ReportingObserver und die Direktive report-to mit dem Header Reporting-Endpoints werden vor allem von Chromium-Browsern unterstützt. In anderen Browsern ist die Unterstützung lückenhaft. Zusätzlich die veraltete Direktive report-uri anzugeben, lohnt sich weiterhin. Dort heißt das Feld aber line-number und steht im Objekt csp-report.
  • Kann fehlen: Den Wert immer auf null bzw. 0 prüfen. Bei blockierten Ressourcen ohne Skriptkontext gibt es keine Zeilennummer.
  • Cross-Origin-Skripte: Wenn der Verstoß aus einem fremden Skript ohne CORS stammt, können sourceFile, lineNumber und columnNumber aus Datenschutzgründen gekürzt oder leer sein.
  • Minifizierter Code: In gebündelten Dateien zeigt die Zeilennummer auf die ausgelieferte Datei, nicht auf den Quellcode. Um die ursprüngliche Stelle zu finden, braucht man Source Maps.
  • Nicht mit dem Event verwechseln: SecurityPolicyViolationEvent.lineNumber liefert dieselbe Information, aber über das Event securitypolicyviolation.
  • Sicherheit: Berichte am Endpunkt kommen vom Client und lassen sich fälschen. Die Felder deshalb vor dem Speichern oder Anzeigen prüfen und escapen.