XSS (DOM) — Impossible
Hoe beveilig je een frontend tegen dit soort lokale DOM-manipulaties?
1. Predict (Voorspel)
De server hoeft hiervoor helemaal niets te doen! De oplossing zit verborgen in de manier waarop we de tekst op het scherm "tekenen" via JavaScript in plaats van het aan de HTML vast te knopen.
In plaats van: document.write(lang)
Doen ontwikkelaars nu dit:
const element = document.getElementById("taalDropdown");
element.textContent = lang; // Of .innerText
Vraag: Waarom zijn .textContent of vergelijkbare eigenschappen immuun voor DOM XSS?
Antwoord
Wanneer je document.write of .innerHTML gebruikt, zegt de browser: "Ik ga deze tekst ontleden en opbouwen alsof het HTML is." Als daar <script> in zit, wekt hij dat tot leven.
Gebruik je .textContent of .innerText, dan zegt de browser: "Dit is uitsluitend platte letter-tekst." Een script tag wordt dan letterlijk als platte tekst op het scherm gezet en absoluut genegeerd door de compiler!
2. Run & Investigate
Start het lab.
Probeer de hash truc of de drop-down escape truc. Het werkt niet meer, want de browser beschouwt jouw injecties simpelweg als platte tekst.
3. ✓ Wat moest je zien?
- Welke payload je ook in de URL of hash zet: geen popup, geen DOM-doorbraak.
- In F12 Elements zie je dat je payload als platte tekst in de dropdown verschijnt — de
<en>worden niet meer als HTML geïnterpreteerd. - De
<select>-structuur blijft heel; je krijgt geen kapotte iframes of escapes meer voor elkaar.
Krijg je tóch een popup? Dan staat het level rechtsboven niet op Impossible.
Wat heb je geleerd?
- DOM XSS is uniek: De aanval bereikt de backend server vaak niet eens (zeker als je de
#hash trick gebruikt). - Backend filters zijn zinloos: Een firewall of server-side check heeft geen enkele waarde als de kwaadaardige code rechtstreeks in de browser van de gebruiker rondzwerft.
- Gebruik veilige JS functies: Vermijd het gebruik van
document.write(),.innerHTMLeneval(). Gebruik altijd data-binders (zoals React gebruikt) of.textContent!