Skip to main content
Blog
Blog

JavaScript-injectie voorkomen: een praktische stapsgewijze gids

Praktische gids om JavaScript-injectie te voorkomen: sluit de XSS-klasse, beperk scripts van derden met CSP en SRI, en inspecteer echte sessies.

Aug 21, 2026 Bijgewerkt Aug 22, 2026 10 min read
JavaScript-injectie voorkomen: een praktische stapsgewijze gids
Inhoudsopgave

Het voorkomen van JavaScript-injectie is niet één taak. Het is het sluiten van meerdere verschillende deuren die allemaal naar dezelfde ruimte leiden: door een aanvaller gecontroleerde code die in de browsers van je bezoekers draait met alle rechten van je eigen pagina. Sommige van die deuren zijn bugs in je code. De meeste zijn scripts die je bewust hebt geladen en die later vijandig werden. Deze gids doorloopt de maatregelen die het risico daadwerkelijk verkleinen, in de volgorde die de meeste bescherming voor de minste moeite biedt, en is eerlijk over waar elke maatregel ophoudt.

Wil je eerst de achtergrond, dan behandelt wat JavaScript-injectie is het mechanisme en elke route die vreemde code een pagina in neemt. Dit artikel is het praktische vervolg: wat je eraan doet.

JavaScript-injectie voorkomen, in het kort

  • Sluit de XSS-klasse in je eigen code. Encodeer bij de uitvoer, gebruik veilige DOM-sinks, saneer niet-vertrouwde HTML en zet Trusted Types aan.
  • Beperk waar script vandaan kan komen. Een strikte, op nonce gebaseerde Content Security Policy blokkeert niet-geautoriseerde scriptbronnen.
  • Zet vast wat je kunt. Subresource Integrity bevriest statische afhankelijkheden van derden op een bekende hash.
  • Verklein de afhankelijkheidsboom. Elk script van derden dat je verwijdert is één injectieroute minder.
  • Monitor de runtime. Bewaak elk script dat in echte browsersessies draait, want preventie kan de compromittering van een vertrouwde leverancier niet bereiken.

De injectieroutes waartegen je je verdedigt

Preventie heeft pas zin als je weet wat je voorkomt. JavaScript wordt geïnjecteerd langs vier brede routes, en elk vraagt om een andere maatregel:

InjectierouteHoe het gebeurtDe maatregel die helpt
Cross-site scripting (XSS)Een fout in je code laat invoer van de aanvaller als script draaienUitvoerencoding, veilige sinks, sanering, Trusted Types
Gecompromitteerd script van derdenEen leverancier van wie je de tag laadt levert kwaadaardige codeAfhankelijkheidsreview, CSP, Subresource Integrity, runtime-monitoring
Magecart / skimmersAanvallers plaatsen kaartstelende code op betaalpagina's, vaak via een gecompromitteerde afhankelijkheidRuntime-payloadmonitoring op de checkout, PCI DSS-maatregelen
Kwaadaardige extensies / clientmalwareCode wordt geïnjecteerd op de eigen machine van de bezoeker, op elke site die hij bezoektRuntime-detectie; je kunt de browser van de bezoeker niet patchen

De eerste route is een codefout die van jou is en die je kunt herstellen. De rest zijn vertrouwensfouten: de code was uitgenodigd, of leeft op een machine die je niet beheert. Dat onderscheid telt, omdat het verklaart waarom het herstellen van je eigen code noodzakelijk maar nooit voldoende is.

Stap 1: Sluit de XSS-klasse in je eigen code

Cross-site scripting is de enige injectieroute die volledig onder jouw controle valt, dus begin hier. XSS gebeurt wanneer data die een gebruiker aanlevert in de pagina wordt geschreven op een plek waar de browser het als code in plaats van tekst behandelt. De oplossingen zijn goed begrepen:

  • Encodeer bij de uitvoer, niet alleen bij de invoer. Dezelfde string is veilig in de ene context en gevaarlijk in de andere, dus encodeer data voor de exacte context waar ze terechtkomt: HTML-body, HTML-attribuut, JavaScript, URL of CSS. Contextbewuste uitvoerencoding is de meest effectieve XSS-maatregel.
  • Gebruik veilige DOM-sinks. Wijs niet-vertrouwde data toe met textContent in plaats van innerHTML, en vermijd eval, document.write en setAttribute op event-handlers. Deze "sinks" zijn de plek waar geïnjecteerde strings uitvoerbaar worden.
  • Saneer HTML die je moet renderen. Wanneer je echt door de gebruiker aangeleverde HTML moet renderen (bijvoorbeeld een rich-text-reactie), haal die dan door een onderhouden sanitizer die script en event-handlers verwijdert, in plaats van je eigen filter te schrijven.
  • Zet Trusted Types aan. Trusted Types zorgen dat gevaarlijke DOM-sinks gewone strings weigeren op browserniveau, zodat een geïnjecteerde payload ze niet kan bereiken, zelfs als een bug door de codereview glipt. Ze worden afgedwongen via een CSP-directive, wat direct naar de volgende stap leidt.

Het herstellen van de XSS-klasse verwijdert de deur die een aanvaller opent door jouw code te misbruiken. Het doet niets aan de deuren die je zelf hebt geopend door het script van iemand anders te laden, en daar komen de meeste moderne client-side-inbreuken vandaan.

Stap 2: Beperk bronnen met een Content Security Policy

Een Content Security Policy vertelt de browser welke bronnen script op je pagina mogen laden en uitvoeren. Een strikte, op nonce gebaseerde CSP is een van de sterkste losse maatregelen die je tegen injectie kunt inzetten: script dat niet van een toegestane bron komt, en dat niet de juiste nonce per verzoek draagt, draait simpelweg niet. Inline <script>-blokken die een aanvaller via een XSS-gat injecteert worden standaard geblokkeerd.

Twee praktische opmerkingen. Ten eerste: geef waar mogelijk de voorkeur aan nonces boven host-allowlists; een brede script-src-allowlist heropent stilletjes routes die je wilde sluiten. Ten tweede, en dat is de belangrijke beperking: CSP autoriseert bronnen, het beoordeelt geen gedrag. Zodra je het domein van een leverancier toestaat zodat hun legitieme script kan draaien, heeft CSP geen manier om te weten of dat script zich gedraagt of je formulier aftapt. Als de leverancier bij de bron wordt gecompromitteerd, staat hun domein nog steeds op je allowlist en laadt de kwaadaardige versie probleemloos. CSP is noodzakelijk. Het is niet het hele antwoord.

Stap 3: Zet statische afhankelijkheden vast met Subresource Integrity

Met Subresource Integrity (SRI) kun je een cryptografische hash koppelen aan een <script>- of <link>-tag. De browser berekent de hash van het gedownloade bestand en weigert het uit te voeren als de hash niet klopt, wat betekent dat een statisch bestand van derden niet kan worden verwisseld voor een gemanipuleerde versie zonder dat de wijziging wordt geblokkeerd.

SRI is uitstekend voor afhankelijkheden die niet veranderen: een specifieke versie van een bibliotheek vastgezet op de exacte hash. De beperking is het spiegelbeeld van die sterkte. Het doet niets voor scripts die bedoeld zijn om te updaten (de meeste analytics, tagmanagers en betaal-SDK's wijzigen hun geleverde bestand regelmatig), en het doet niets voor scripts die dynamisch door andere scripts worden geladen. Gebruik SRI overal waar je een versie kunt vastzetten. Verwacht niet dat het de delen van je stack dekt die zichzelf updaten.

Stap 4: Verklein en review de afhankelijkheidsboom

Elk script van derden op je pagina is een injectieroute met alle rechten van de pagina. De goedkoopste beschikbare preventie is er minder te hebben.

  • Inventariseer wat je daadwerkelijk laadt. De meeste teams zijn verrast door hoeveel scripts er op een typische pagina draaien, en door hoeveel ervan niet direct maar door een ander script worden geladen (een tagmanager die een leverancier laadt die weer een leverancier laadt).
  • Verwijder wat je niet nodig hebt. Een ongebruikte marketingpixel of een verlaten A/B-testtool is puur risico zonder voordeel. Het verwijderen elimineert een injectieroute volledig.
  • Minimaliseer de impactradius van de tagmanager. Een gecompromitteerd tagmanager-account kan "gewoon nog een tag" injecteren die routineus lijkt. Beperk wie mag publiceren en review wat ze publiceren.

Deze stap heeft geen nadeel en geen enkele maatregel per script kan hem vervangen: een script dat niet op de pagina staat kan niet degene zijn die wordt gecompromitteerd.

Stap 5: Monitor de runtime met payloadinspectie in echte sessies

Stappen één tot en met vier verkleinen de kans. Geen van hen kan het geval bereiken dat de ergste client-side-inbreuken veroorzaakt: een script dat je legitiem vertrouwt, van een bron die je legitiem hebt toegestaan, dat kwaadaardig wordt nadat het al is geladen. CSP laat het door omdat de bron is toegestaan. SRI mist het omdat het script is ontworpen om te updaten. Je eigen code is schoon. De enige plek die overblijft om het te betrappen is waar de injectie daadwerkelijk landt, de browser, op het moment dat het script draait.

Dat is wat runtime-monitoring doet. Het bouwt een inventaris van elk script dat in echte gebruikerssessies draait, registreert wat elk doet en waar het data naartoe stuurt, en waarschuwt wanneer een nieuw script verschijnt, de code van een bekend script verandert, of data naar een onverwachte bestemming begint te stromen. Dit is de laag die Magecart-achtige skimmers en aanvallen van gecompromitteerde leveranciers betrapt die alle preventieve maatregelen hierboven doorlaten.

Tools aan de serverkant kunnen dit niet leveren. Een webapplicatiefirewall of een serverscan ziet de HTML die je hebt geleverd, niet de payload die een gecompromitteerde leverancier later verwisselt of de code die een extensie op de machine van de bezoeker injecteert. Detectie moet op de browserlaag plaatsvinden, in echte sessies.

Waar cside past: scriptmonitoring in echte sessies

cside is één first-party JavaScript-snippet die de runtime-laag van deze checklist levert. Het vervangt je CSP, je uitvoerencoding of je SRI-hashes niet; het is de maatregel die bewaakt wat je toegestane scripts daadwerkelijk doen zodra ze draaien, wat geen van de andere kan zien.

De scriptmonitoring van cside inventariseert elk script dat in echte browsersessies draait, analyseert de volledige scriptpayload en waarschuwt bij nieuwe domeinen, gewijzigde code en onverwachte datastromen. Het werkt in twee operationele modellen: de Script Method haalt scripts van derden op en analyseert ze aan de kant van cside voordat ze in de sessie draaien, en de Scan Method voor teams die een lichtere footprint verkiezen. Het wordt ingezet als één scripttag vanaf je eigen origin, zonder DNS-wijziging; cside haalt de scripts van derden die je pagina laadt op en analyseert ze, maar staat niet vóór het verkeer van je site en fungeert niet als proxy.

Op betaalpagina's is deze runtime-inventaris ook een nalevingsvereiste. De eisen 6.4.3 en 11.6.1 van PCI DSS 4.0.1 bestaan juist omdat geïnjecteerd script op de betaalpagina onzichtbaar is voor elke maatregel aan de serverkant: 6.4.3 vraagt je om elk script op je betaalpagina's te beheren en te autoriseren, en 11.6.1 vraagt je om ongeautoriseerde wijzigingen aan die scripts en de paginakoppen te detecteren. Scriptmonitoring in echte sessies is het directe antwoord op beide.

Preventiechecklist

Het voorkomen van JavaScript-injectie is gelaagd, en de lagen overlappen niet:

  1. Encodeer uitvoer en gebruik veilige DOM-sinks om de XSS-klasse in je eigen code te sluiten.
  2. Zet een strikte, op nonce gebaseerde CSP in om niet-geautoriseerde scriptbronnen te blokkeren.
  3. Voeg Subresource Integrity toe om statische afhankelijkheden van derden vast te zetten.
  4. Verklein en review de afhankelijkheidsboom zodat er minder te compromitteren is.
  5. Monitor echte browsersessies zodat een vertrouwd script dat vijandig wordt, wordt betrapt op het moment dat het handelt.

Krijg de eerste vier goed en je hebt de meeste deuren gesloten. Voeg de vijfde toe en je kunt de enige deur zien die preventie nooit volledig kan vergrendelen: de vertrouwde leverancier die wordt gecompromitteerd nadat je hem hebt binnengelaten.

Verder lezen

Mike Kutlu
Client-Side Security Consultant

Client-side security consultant at cside. 10+ years of experience implementing technology solutions for enterprises (previously at Oracle, Cloudflare, and Splunk). Now helping teams use client-side intelligence to catch & reduce fraud.

FAQ

Frequently Asked Questions

Er is geen enkele maatregel die elke route afsluit, omdat de routes verschillende problemen zijn. Om cross-site scripting te stoppen corrigeer je hoe je eigen code invoer en uitvoer verwerkt: encodeer bij de uitvoer, gebruik veilige DOM-sinks en zet Trusted Types aan. Om injectie via de scripts van derden die je al laadt te stoppen, beperk je bronnen met een Content Security Policy, zet je statische afhankelijkheden vast met Subresource Integrity, en monitor je wat die scripts tijdens runtime daadwerkelijk doen. Het eerste is een codefix; de rest zijn vertrouwensmaatregelen. Je hebt beide nodig.

Nee. Een strikte, op nonce gebaseerde CSP is een van de sterkste losse maatregelen die je kunt inzetten, omdat het script van niet-geautoriseerde bronnen blokkeert. Maar CSP autoriseert bronnen, het beoordeelt geen gedrag: zodra je het domein van een leverancier toestaat, kan CSP niet zien of het script van die leverancier je betaalformulier aftapt. Als een toegestaan script bij de bron wordt gecompromitteerd, laat CSP het door. Daarom moeten bronbeperkingen worden gecombineerd met runtime-monitoring van wat toegestane scripts daadwerkelijk doen.

Magecart en supply-chain-aanvallen misbruiken geen bug in je code; ze misbruiken een script dat je hebt uitgenodigd. Preventie gaat daar over het verkleinen en bewaken van de afhankelijkheidsboom: verwijder scripts van derden die je niet nodig hebt, zet de scripts die je kunt vast met Subresource Integrity, beperk bronnen met CSP, en monitor elk script dat in echte browsersessies draait zodat een nieuw domein of een gewijzigde payload een melding geeft. De scriptmonitoring van cside is voor die laatste laag gebouwd.

Meestal niet, omdat injectie vaak plaatsvindt nadat de pagina je server heeft verlaten, in de browser van de bezoeker. Een webapplicatiefirewall of serverscan ziet de HTML die je hebt geleverd, niet het script dat een gecompromitteerde leverancier een uur later verwisselt, of de code die de extensie van een aanvaller op de machine van de bezoeker injecteert. Geïnjecteerd script detecteren vereist zicht op de browserlaag: een inventaris van elk script dat in echte sessies draait en waar elk data naartoe stuurt.

JavaScript-injectie is elke situatie waarin door een aanvaller beheerde code in de browser van een bezoeker draait met dezelfde rechten als de scripts van je eigen pagina. Het bereikt de pagina via meerdere routes: een cross-site scripting-fout in je eigen code, een script van derden dat je laadt en dat kwaadaardig wordt, een Magecart-skimmer die op een betaalpagina is geplaatst, of een browserextensie op de machine van de bezoeker. Omdat de geïnjecteerde code de toegang van je pagina tot de DOM, cookies en formuliervelden erft, kan het lezen wat gebruikers typen, verzoeken omleiden of data exfiltreren, en daarom moet preventie elke route aanpakken, niet slechts één.

Cross-site scripting is een bug in je eigen applicatie: het laat de invoer van een aanvaller op de pagina schrijven waar de browser die als code behandelt, dus je verhelpt het door te veranderen hoe je code invoer en uitvoer verwerkt. Een gecompromitteerd script van derden is anders: het is code die je bewust van een leverancier hebt geladen en die vijandig werd nadat je het hebt uitgenodigd, ofwel omdat de leverancier is gehackt of omdat het bestand onderweg is gemanipuleerd. XSS is een codefout die van jou is; een gecompromitteerde afhankelijkheid is een vertrouwensfout in iets dat je niet kunt patchen. Ze vereisen verschillende maatregelen, en daarom dekt het sluiten van XSS nooit volledig het risico van derden.

Output-encoding zet tekens die een browser anders als markup of code zou behandelen om in hun onschadelijke weergave-equivalenten, voor de specifieke context waar de data belandt: HTML-body, attribuut, JavaScript, URL of CSS. Encoderen voor de verkeerde context laat een gat, dus contextbewuste encoding bij de uitvoer is de kern-XSS-verdediging. Trusted Types voegen een tweede laag toe op browserniveau: ze zorgen dat gevaarlijke DOM-sinks zoals innerHTML gewone strings weigeren, zodat een geïnjecteerde payload ze niet kan bereiken, zelfs als een bug de review passeert. Trusted Types worden afgedwongen via een Content Security Policy-directive, dus de twee maatregelen werken samen.

Subresource Integrity zet een script of stylesheet vast op een cryptografische hash, en de browser weigert het bestand uit te voeren als de hash niet klopt, zodat een statische afhankelijkheid niet kan worden verwisseld voor een gemanipuleerde versie. De beperking is de keerzijde van die kracht: het werkt alleen voor bestanden die nooit veranderen. Scripts die zijn ontworpen om te updaten (de meeste analytics, tagmanagers en betaal-SDK's wijzigen hun geleverde bestand regelmatig) kunnen niet worden vastgezet, en SRI doet niets voor scripts die andere scripts dynamisch tijdens runtime laden. Gebruik het overal waar je een versie kunt vastzetten, maar verwacht niet dat het de zelf-updatende delen van je stack dekt, wat precies is waar aanvallen via gecompromitteerde leveranciers doorgaans landen.

CSP staat bronnen toe en SRI zet statische bestanden vast, dus beide laten een script door dat je legitiem vertrouwt en dat kwaadaardig wordt nadat het is geladen: CSP ziet nog steeds een toegestane bron, en SRI kan een bestand dat bedoeld is om te updaten niet vastzetten. Monitoring in echte sessies bewaakt de enige plek waar die fout opduikt: de browser, op het moment dat het script draait. Het bouwt een inventaris op van elk script dat in echte gebruikerssessies draait, registreert wat elk doet en waar het data naartoe stuurt, en waarschuwt wanneer een nieuw script verschijnt, de code van een bekend script verandert, of data naar een onverwachte bestemming stroomt. Dat is de laag die Magecart-achtige skimmers en aanvallen via gecompromitteerde leveranciers opvangt die de preventieve maatregelen niet kunnen zien.

PCI DSS 4.0.1 voegde twee eisen toe juist omdat geïnjecteerd script op een betaalpagina onzichtbaar is voor maatregelen aan de serverkant. Eis 6.4.3 vraagt je om elk script dat op je betaalpagina's draait te beheren en te autoriseren, en 11.6.1 vraagt je om ongeautoriseerde wijzigingen aan die scripts en aan de HTTP-headers van de pagina te detecteren. Beide beschrijven zicht op de browserlaag: een inventaris van wat er daadwerkelijk in echte sessies draait en een melding wanneer het verandert. Scriptmonitoring in echte sessies is het directe antwoord op beide, en daarom passen teams met een PCI-deadline het meestal eerst toe op de betaalflow.

Ja. Een kwaadaardige of te ruim gerechtigde browserextensie draait op de eigen machine van de bezoeker en kan script injecteren in elke site die hij opent, inclusief die van jou, met volledige toegang tot de gerenderde pagina. Je kunt dit niet voorkomen zoals je je eigen code verhelpt of een leverancier vastzet, want de extensie leeft volledig buiten jouw controle: er is niets op je server om te patchen. Wat je wel kunt doen is het detecteren: runtime-monitoring die observeert wat er in echte sessies draait, kan script markeren dat geen enkel legitiem deel van je pagina heeft geladen, wat vaak het enige signaal is dat een extensie de sessie van een bezoeker manipuleert.

Bevestig eerst wat je ziet: gebruik zicht op de browserlaag om het exacte script, de bron waar het vandaan kwam en waar het data naartoe stuurt te identificeren, zodat je handelt op bewijs in plaats van op een gok. Als het een gecompromitteerde afhankelijkheid van derden is, verwijder of blokkeer dat script onmiddellijk en trek elke inloggegevens in die het had kunnen blootleggen; als het een XSS-fout is, patch de kwetsbare invoerverwerking en herstel de betrokken output-encoding. Behandel het op betaalpagina's als een mogelijk incident met kaarthoudergegevens onder PCI DSS en volg je responsplan. Sluit vervolgens het gat dat het toeliet (een ontbrekende CSP-directive, een niet-vastgezette afhankelijkheid of een tagmanager-account met te veel publicerende gebruikers) en houd monitoring in echte sessies op zijn plaats zodat een herhaling wordt opgevangen op het moment dat het optreedt.

Monitor en beveilig je third-party scripts

Gain full visibility and control over every script delivered to your users to enhance site security and performance.

Start gratis, of probeer Business met een proefperiode van 14 dagen.

cside-dashboardinterface met scriptmonitoring en beveiligingsanalyses
Related Articles
Boek een demo

Wil je dit doornemen met een engineer?

Dertig minuten, op je eigen site. Geen slides.

We laten je zien:

Welke scripts van derden er nu op je site draaien
Hoe je ervoor staat op PCI DSS 6.4.3 en 11.6.1
Welk deel van je verkeer uit bots en AI-agents bestaat

Liever gewoon een vraag stellen?

Vrije momenten zoeken…

Alleen echte mensen. Wij merken het.

Lukt het boeken niet? Agenda in een nieuw tabblad openen

Wat wil je oplossen?

Vertel het ons in één zin, dan komen we terug met iets bruikbaars in plaats van een standaardverhaal.

Waar we meestal mee helpen:

Zien welke scripts van derden op je site draaien
Bewijs voor PCI DSS 6.4.3 en 11.6.1
Bots, AI-agents en accountovername

Liever meteen een moment inplannen? Kies een tijdstip