DOM-based XSS is een cross-site scripting-kwetsbaarheid die volledig in client-side code zit. De eigen JavaScript van de pagina leest invoer die de aanvaller kan beïnvloeden — meestal uit de URL — en schrijft die naar de DOM via een onveilige sink zoals innerHTML, waardoor het script van de aanvaller wordt uitgevoerd. Anders dan bij reflected of stored XSS hoeft de kwaadaardige payload nooit in een serverrespons te verschijnen.
Hoe werkt een DOM XSS-aanval?
De kwetsbaarheid is een datastroom van een source die de aanvaller beheerst naar een sink die tekst als code of markup interpreteert:
// vulnerable: fragment flows straight into a sink
const name = decodeURIComponent(location.hash.slice(1));
document.querySelector("#welcome").innerHTML = "Hello " + name;
// https://example.com/#<img src=x onerror=stealCookies()>
Veelvoorkomende sources: location.hash, location.search, document.referrer, window.name, postMessage-data en client-side opslag. Veelvoorkomende sinks: innerHTML/outerHTML, document.write, eval en Function, jQuery's .html(), en attribuutschrijfacties die handlers of URL's aanmaken (onclick, href met javascript:).
Omdat het URL-fragment nooit naar de server wordt verzonden, kan een payload na # de pagina exploiteren terwijl de server een volkomen normale request ziet.
Reflected vs stored vs DOM-based XSS
| Reflected XSS | Stored XSS | DOM-based XSS | |
|---|---|---|---|
| Waar de payload leeft | In de request, teruggekaatst door de server | In de database van de server | In client-side invoer (vaak het URL-fragment) |
| Bevat de serverrespons de payload? | ✓ | ✓ | Vaak ✗ |
| Zichtbaar voor WAF's / serverlogs | Meestal | Meestal | Vaak niet |
| Waar het wordt opgelost | Server-side output-encoding | Server-side sanitization + encoding | Client-side code: veilige sinks, sanitization |
Waarom DOM XSS makkelijk te missen is
Server-side verdedigingen inspecteren requests en responses; DOM XSS kan beide omzeilen. Frameworks verkleinen het risico — React en soortgelijke escapen standaard — maar dangerouslySetInnerHTML, verkeerd templategebruik en de third-party scripts op de pagina brengen het terug. En een moderne pagina draait tientallen scripts die je niet zelf hebt geschreven: een onveilige sink in een daarvan is een onveilige sink op jouw pagina. Dat compositieprobleem is de kern van client-side security.
Hoe je het voorkomt en detecteert
- Geef de voorkeur aan veilige sinks:
textContentboveninnerHTML; vermijdevalen uit strings opgebouwde handlers volledig. - Sanitize wanneer HTML onvermijdelijk is (DOMPurify of de opkomende Sanitizer API), en gebruik Trusted Types waar ondersteund — die maken van onveilige sink-schrijfacties beleidsschendingen.
- Zet een strikte Content Security Policy in met nonces; die blokkeert veel payloadstijlen, maar niet de hele aanvalsklasse.
- Houd runtimegedrag in de gaten: exploitatie manifesteert zich uiteindelijk als scripts die dingen doen die niet horen — nieuwe uitgaande requests, DOM-schrijfacties in betaalformulieren, onverwachte listeners. De client-side monitoring van cside observeert echte sessies op browserniveau, de enige plek waar een aanval die alleen in de DOM bestaat überhaupt zichtbaar is.







