Einführung
Ein DOM-basierter XSS-Spickzettel ist Ihre beste Referenz wenn Sie den Schutz vor clientseitiger Skriptinjektion aufspüren, verhindern und automatisieren wollen. Im Wesentlichen geht es darum, festzustellen, wo benutzergesteuerte Eingaben (ein Quelle) fließt in eine gefährliche API (a Waschbecken), ersetzen Sie sie durch sichere Muster (verwenden Sie textInhalt, createElementoder Sanitizer), und integrieren Sie Prüfungen in Ihren Build-, Laufzeit- und Pentest-Workflow. Da DOM XSS vollständig im Browser stattfindet und viele herkömmliche serverseitige Filter umgeht, wird Ihr Front-End zur letzten Verteidigungslinie - und der Ort, an dem es den meisten Teams noch an Automatisierung mangelt.
Was ist DOM-Based XSS und warum es wichtig ist
Laut PortSwigger tritt DOM-basiertes Cross-Site-Scripting auf, wenn "JavaScript nimmt Daten aus einer vom Angreifer kontrollierbaren Quelle, z. B. einer URL, und leitet sie an eine Senke weiter, die die Ausführung von dynamischem Code unterstützt, z. B. eval() oder innerHTML." portswigger.net Das OWASP DOM-based XSS Prevention Cheat Sheet unterstreicht, dass der Hauptunterschied zu gespeicherten/reflektierten XSS darin besteht Client-seitige Injektion zur Laufzeit. cheatsheetseries.owasp.org+1
In modernen Anwendungen - Single Page Apps (SPAs), starker Einsatz von Widgets von Drittanbietern, dynamischer DOM-Aufbau - wächst das Risiko: Nutzdaten erreichen möglicherweise nie Ihre Serverprotokolle, herkömmliche WAFs können sie übersehen, und Entwickler berücksichtigen sie oft nicht ausreichend. Fragment-Bezeichner, postMessage fließt, oder fenster.namealle gängigen Quellen. Das Erkennen dieser Veränderung ist der erste Schritt zur Messung Ihrer Sicherheitsreife.
Kartierung der Bedrohung: Quellen → Senken
Sichere Kodierung beginnt mit einer mentalen Karte von Quellen (wo die Eingaben des Angreifers eingehen) und Waschbecken (wo die Ausführung erfolgt). Ein Sicherheitsblog fasst zusammen: "Die Quelle ist jeder Ort auf einer Webseite, an dem Benutzereingaben hinzugefügt werden können ... Die Senke ist der Ort, an dem die in die Quelle eingefügten Daten landen ... und wenn sie nicht bereinigt werden, kann dies zu einer DOM-basierten XSS-Schwachstelle führen." Mittel
Nachfolgend finden Sie eine kompakte Tabelle, die Sie an Ihrem Arbeitsplatz und in den Checklisten für die Überprüfung aufbewahren sollten:
| Quelle (Einstiegspunkt) | Senke (gefährliche API) |
|---|---|
| location.hash, location.search, URLSearchParams | innerHTML, insertAdjacentHTML, outerHTML |
| postMessage, fenster.name | eval(), new Funktion(), setTimeout(string) |
| document.referrer, localStorage, sessionStorage | setAttribute('on...'), element.src = ... |
| Ungeprüfte Widget-Daten von Drittanbietern | Jede DOM-Einfügung oder implizite Codeausführung |
Wie OWASP betont, gibt es keine einzelne Technik, die XSS verhindert: Sie müssen geeignete Senken, Kodierung, Bereinigung und sichere APIs kombinieren. spickzettel-serie.owasp.org
Angriffsmuster aus der realen Welt mit Code und Korrekturen
Beispiel A - jQuery-Selektorinjektion über URL-Fragment
Verwundbares Snippet:
js
$(window).on('hashchange', () => {
const target = $(location.hash); // benutzergesteuert
target[0].scrollIntoView();
});
Ein Angreifer kann https://site/page.html#<img src="x" onerror="alert(1)"> - jQuery behandelt den Hash als HTML/Selektor und die onerror Auslöser.
Reparieren:
js
const raw = location.hash.slice(1);
const safeId = /^[A-Za-z0-9_-]+$/.test(raw) ? raw : null;
if (safeId) {
const target = document.getElementById(safeId);
if (target) target.scrollIntoView();
}
Schlüssel: validieren, Hash als Bezeichner und nicht als HTML behandeln.
Beispiel B - postMessage → eval-Kette
Verwundbares Snippet:
js
window.addEventListener('message', e => {
eval(e.data); // gefährlich
});
Festgelegte Version:
window.addEventListener('message', event => {
if (event.origin !== '') return;
versuchen {
const msg = JSON.parse(event.data);
handleMessage(msg);
} catch {
console.warn('Ungültiges Nachrichtenformat');
}
});
Vermeiden Sie eval, Herkunft prüfen, sicheres Parsing verwenden.
Beispiel C - Editor/Vorschau-XSS im Markdown-Kontext
Verwundbar:
js
preview.innerHTML = marked(userInput);
Sicher:
js
import DOMPurify from 'dompurify';
const dirty = marked(userInput);
const clean = DOMPurify.sanitize(dirty);
preview.innerHTML = clean;
Wenn Sie benutzergeneriertes HTML zulassen, ist eine Bereinigung erforderlich.
Einsetzbare Implementierungen: Einsatzfähig machen
Sicherer DOM-Helfer - safe-dom.js
js
import DOMPurify from 'dompurify';
export function setSafeHTML(el, dirty) {
const clean = DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b','i','a','p','ul','li','code','pre','img'],
ALLOWED_ATTR: ['href','src','alt','title','rel'],
FORBID_ATTR: ['onerror','onclick','style']
});
el.innerHTML = clean;
}
export function setText(el, text) {
el.textContent = String(text ?? '');
}
export function safeSetAttribute(el, name, val) {
if (/^on/i.test(name)) throw new Error('Event handler attribute not allowed');
el.setAttribute(name, String(val));
}
Verwenden Sie diese Bibliothek, um sichere DOM-Vorgänge zu zentralisieren und menschliche Fehler zu reduzieren.
Statische Durchsetzung - ESLint-Beispiel
js
// .eslintrc.js
Regeln: {
'no-restricted-syntax': [
Fehler",
{ selector: "AssignmentExpression[left.property.name='innerHTML']", message: "Verwende safe-dom.setSafeHTML oder textContent." },
{ selector: "CallExpression[callee.name='eval']", message: "Vermeide eval()" },
{ selector: "CallExpression[callee.property.name='write']", message: "Vermeide document.write()" }
]
}
Kombinieren Sie mit Pre-Commit-Hooks (Husky, stufenweise), um gefährliche Muster zu blockieren.
CI / Puppeteer-Test - GitHub-Aktionen
.github/workflows/dom-xss.yml löst einen Puppeteer-Test aus:
// tests/puppeteer/dom-xss-test.js
js
const puppeteer = require('puppeteer');
(async ()=>{
const browser = await puppeteer.launch();
const page = await browser.newPage();
const logs = [];
page.on('console', msg => logs.push(msg.text()));
await page.goto(${URL}/page.html#<img src="x" onerror="console.log("XSS")">);
await page.waitForTimeout(1000);
if (logs.some(l=>l.includes('XSS'))) process.exit(2);
await browser.close();
})();
Fail build on detection.
Laufzeitüberwachung - MutationObserver
js
(function(){
const obs = new MutationObserver(muts=>{
muts.forEach(m=>{
m.addedNodes.forEach(n=>{
if(n.nodeType===1){
const html = n.innerHTML || '';
if(/on(error|click|load)|<script\\b/i.test(html)){
navigator.sendBeacon('/_monitoring/xss', JSON.stringify({
url: location.href, snippet: html.slice(0,200)
}));
}
}
});
});
});
obs.observe(document.documentElement, {childList:true, subtree:true});
})();
Nützlich beim Staging, um auf unerwartete DOM-Injektionen hinzuweisen.
Browser-Sicherheitshärtung - CSP & vertrauenswürdige Typen
CSP-Kopfzeile:
pgsql
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-XYZ'; object-src 'none'; base-uri 'self';
Vertrauenswürdige Typen Schnipsel:
js
window.trustedTypes?.createPolicy('safePolicy', {
createHTML: s => { throw new Error('Direct HTML assignment blocked'); },
createScript: s => { throw new Error('Direct script creation blocked'); }
});
Damit werden nicht vertrauenswürdige Senken standardmäßig abgelehnt.
Sicherheit von Schriften Dritter - SRI
bash
openssl dgst -sha384 -binary vendor.js | openssl base64 -A
Verwenden Sie <script src="vendor.js" integrity="sha384‑..." crossorigin="anonymous"></script> zum Anstecken und Überprüfen.
Integration mit Penligent für die Automatisierung
Wenn Ihr Team Penligent verwendet, können Sie Ihren DOM XSS-Schutz zu einer kontinuierlichen Pipeline ausbauen. Der Forschungsartikel von Penligent zeigt, wie "Erkennung von DOM-basiertem XSS über Runtime Taint Tracking ... serverseitige Techniken können clientseitige Injektionen nicht zuverlässig abfangen." Sträflich
Beispiel-Workflow:
- In CI trigger a Penligent scan with ruleset
dom‑xss, supplying payloads like#<img src="x" onerror="alert(1)">. - Penligent executes headless flows, generates PoC, returns findings via webhook.
- CI analyses findings: if severity ≥ high, fail build and annotate PR with payload + sink + fix recommendation (e.g., “replace
innerHTMLmitsafe-dom.setSafeHTML). - Developers fix, run CI again, merge only when green.
This closes the loop: from reference (this cheat sheet) → code policy → automated detection → organized remediation.
Schlussfolgerung
The front‑end is no longer “just UI”. It is an attack surface. This cheat sheet walks you through understanding client‑side injection, replacing dangerous sinks, building safe helper libraries, deploying static/CI/runtime detection, and automating with a platform like Penligent. Your next steps: scan your codebase for banned sinks (innerHTML, eval), adopt a safe‑dom library, enforce lint rules, integrate headless tests and real pentest logic, monitor production/staging, and pin third‑party resources. Protecting DOM XSS is about making it impossible to slip through—not just relying on chance.

