Wat is XSS en hoe bescherm je je applicatie?

Auteur: Gepubliceerd

Kort samengevat: XSS (Cross-Site Scripting) is een kwetsbaarheid waardoor de browser onvertrouwde code uitvoert in de context van de bezochte website. Dit ontstaat meestal wanneer een applicatie gebruikersgegevens behandelt als onderdeel van de pagina of als code, in plaats van als gewone tekst. Bescherming draait vooral om het veilig weergeven van gegevens, niet alleen om het blokkeren van verdachte invoer.

Hoe XSS werkt en wat een aanvaller kan doen

De browser interpreteert HTML als de structuur van de pagina en JavaScript als uit te voeren instructies. Als een applicatie ongecontroleerde inhoud invoegt op een plek waar die als code wordt geïnterpreteerd, kan een aanvaller de werking van de pagina bij een andere gebruiker beïnvloeden. Zulke inhoud kan afkomstig zijn uit een reactie, een adresparameter, een profielnaam of een antwoord van een externe dienst.

Code die via XSS wordt uitgevoerd, werkt in de context van de aangevallen website. Die code kan beschikbare gegevens op de pagina lezen, de inhoud veranderen, een vals inlogformulier tonen of handelingen uitvoeren met de rechten van de ingelogde gebruiker. De daadwerkelijke gevolgen hangen af van de functies van de applicatie en de toegepaste beveiliging.

Dit betekent niet automatisch dat de server of de hele computer wordt overgenomen. Het probleem zit vooral in het vertrouwen dat de browser stelt in code die door de betreffende website wordt uitgevoerd. Een gebruiker kan het juiste adres openen en toch op een pagina met kwaadaardige inhoud terechtkomen.

De drie meest beschreven vormen van XSS

Deze indeling helpt vast te stellen waar de gevaarlijke inhoud vandaan komt en waar de applicatie die verwerkt:

Deze begrippen sluiten elkaar niet altijd uit. ‘Opgeslagen’ en ‘gereflecteerd’ beschrijven vooral hoe de gegevens worden aangeleverd, terwijl ‘DOM-based’ aangeeft waar de onveilige verwerking plaatsvindt. Ook inhoud die in een database is opgeslagen, kan tot DOM-based XSS leiden.

Eenvoudig voorbeeld: tekst behandeld als HTML

Stel dat een applicatie een gebruikersnaam weergeeft. Voer het volgende voorbeeld alleen uit in je eigen testomgeving of op een plek waarvoor je uitdrukkelijk toestemming hebt:

const naam = '<img src="x" onerror="alert(\'XSS-test\')">';
const element = document.querySelector('#begroeting');
element.innerHTML = naam;

De eigenschap innerHTML laat de browser de waarde interpreteren als HTML. Als de afbeelding niet wordt geladen, kan de foutafhandeling alert uitvoeren: er verschijnt dan een venster met een melding. Dit demonstreert het uitvoeren van code, niet het stelen van gegevens. Aanvullende beveiliging van de browser of de website kan dit blokkeren.

Als de naam gewone tekst moet zijn, is dit de juiste oplossing:

const naam = '<img src="x" onerror="alert(\'XSS-test\')">';
const element = document.querySelector('#begroeting');
element.textContent = naam;

De eigenschap textContent geeft de opgegeven tekenreeks weer zonder een afbeelding aan te maken en zonder de instructie erin uit te voeren. Het verschil is wezenlijk: gegevens blijven gegevens. Je hoeft niet te raden welke woorden of tags gevaarlijk kunnen zijn.

Hoe bescherm je een applicatie tegen XSS?

Stem de bescherming af op de plek waar de gegevens worden gebruikt. Uitvoercodering houdt in dat speciale tekens zo worden weergegeven dat ze niet als syntaxis worden geïnterpreteerd. Voor tekst in HTML gelden andere regels dan voor een attribuutwaarde, een URL of een fragment JavaScript. Alleen de punthaken < en > vervangen biedt niet in al deze situaties bescherming.

Gebruik voor gewone tekst veilige templatemechanismen en interfaces zoals textContent. Automatische codering in een framework helpt, maar kan worden omzeild met een functie die onbewerkte HTML invoegt. Zulke uitzonderingen vereisen een afzonderlijke controle.

Als gebruikers daadwerkelijk opmaak met HTML nodig hebben, gebruik dan een actief onderhouden bibliotheek voor sanitisatie, zoals DOMPurify. Sanitisatie verwijdert niet-toegestane elementen en attributen volgens vastgestelde regels. Een zelfgemaakt filter op basis van een paar reguliere expressies biedt geen gelijkwaardige bescherming.

Validatie, oftewel controleren of gegevens een toegestaan formaat hebben, blijft nuttig: een leeftijdsveld moet een getal accepteren en een linkadres moet een toegestaan schema gebruiken. Validatie vervangt echter niet het veilig weergeven van gegevens. Alleen het formulier beveiligen is ook niet genoeg, want gegevens kunnen via andere routes in de applicatie terechtkomen.

Aanvullende beveiligingslagen beperken de gevolgen van fouten. Met CSP (Content Security Policy) kun je regels voor het uitvoeren van scripts vastleggen, maar de effectiviteit hangt af van de configuratie. Het attribuut HttpOnly voorkomt dat JavaScript een cookie uitleest, maar verhindert niet dat kwaadaardige code allerlei handelingen binnen de actieve sessie uitvoert.

Waar begin je met het controleren van je eigen website?

Volg één veld vanaf de ontvangst van de gegevens tot elke plek waar ze worden weergegeven. Een reactie kan onder een artikel veilig zijn, maar in het moderatiepaneel of het voorbeeld van een melding onveilig. Controleer ook waar innerHTML wordt gebruikt en waar functies worden ingezet die automatische codering omzeilen.

De volgende stap is een test in een geïsoleerde omgeving: stel vast of de ingevoerde inhoud als tekst verschijnt of de structuur van de pagina verandert. Voeg na de correctie een regressietest toe die detecteert of deze gegevens opnieuw als HTML worden behandeld.

Zie ook: Wat is 2FA?

Lees ook

Lees hoe PHP-FPM PHP-verzoeken verwerkt, verschilt van een webserver en hoe je processen afstemt op verkeer en hostingcapaciteit.
Ontdek hoe BIND als open DNS-serversoftware domeinen beheert, welke rollen het vervult en wanneer zelf beheren zinvol is.
Lees wat het Poolse REGON-register en -nummer betekenen, hoe ze verschillen van NIP en KRS en hoe je bedrijfsgegevens controleert.