Een Content-Security-Policy toevoegen zonder je site kapot te maken

Een beveiligingsscan, een Lighthouse-rapport of je hostingpartij meldt dat je site geen Content-Security-Policy heeft. De oplossing lijkt één header. Kopieer een beleid van een blog, zet het live, klaar. Daarna laadt het boekingsformulier niet meer, verdwijnt de chatwidget of, erger, breekt er zichtbaar niets en tellen je Google Ads geen conversies meer. Op onze eigen site deden we bijna precies dat.
Het korte antwoord: begin met Content-Security-Policy-Report-Only, niet met de echte header. Die meldt wat het beleid zou blokkeren, zonder te blokkeren. Verzamel die meldingen minstens een week van echte bezoekers, op elk type pagina, voeg toe wat legitiem is en schakel pas daarna over op afdwingen.
Wat een Content-Security-Policy doet
Het is een HTTP-header die de browser vertelt van welke bronnen een pagina scripts, stijlen, afbeeldingen, lettertypen, frames en verbindingen mag laden. Lukt het een aanvaller een script te injecteren (via een gehackte plugin, een gecompromitteerd script van een derde of een formulier dat invoer niet schoonmaakt), dan weigert de browser het uit te voeren of data naar een onbekende server te sturen. Het is een van de sterkste verdedigingen tegen cross-site scripting en kaartskimmers op checkouts.
Geen CSP hebben komt vaak voor. Toen we 1.482 webshops scanden vlak voor Black Friday, kreeg ongeveer een derde een melding voor een ontbrekende Content-Security-Policy.
Waarom "gewoon de header toevoegen" sites breekt
Een beleid is een whitelist. Alles wat je vergeet wordt geblokkeerd, onzichtbaar voor de bezoeker, met alleen een regel in de browserconsole. De gebruikelijke slachtoffers:
- Analytics- en advertentietags. Google Analytics, Google Ads, Meta Pixel en Microsoft Clarity laden van meerdere hosts en sturen vaak door naar nog meer.
- Embeds. Boekingstools (Calendly), kaarten, YouTube, chatwidgets en betaal-iframes hebben elk hun eigen frame- en scriptbronnen nodig.
- Inline scripts. Veel frameworks en CMS'en zetten kleine scripts direct in de pagina. Een strikt beleid blokkeert ze, tenzij je
'unsafe-inline'toestaat of een nonce toevoegt (een willekeurige waarde per paginaweergave). - Pagina's die niemand test. De contactpagina, de bedankpagina na een formulier, de checkout. Op die pagina's laden vaak juist de conversie- en betaalscripts.
Wat er op onze eigen site gebeurde
Onze site draait sinds juli 2026 met een report-only beleid. De eerste versie bouwden we op basis van een volledige netwerktrace van productie, niet op een gok. Dit is wat de trace en de rapporten opvingen. Elk daarvan had iets gebroken als we vanaf dag één hadden afgedwongen:
- De Google Ads-conversieping gaat alleen af op de contactpagina. Een check van de homepage ziet hem nooit. Afdwingen zonder die host had Ads onze belangrijkste conversie doen missen: een contactaanvraag.
- Microsoft Clarity stuurt door naar een Bing-host.
*.clarity.mstoestaan is niet genoeg; de ID-sync springt naarc.bing.com. - De Ads-remarketingpixel gebruikt het landendomein van de bezoeker, zoals
google.beofgoogle.co.th, nietgoogle.com. CSP heeft daar geen wildcard voor, dus we noemen de landen waar we verkopen en accepteren een klein gat in de doelgroepdata voor de rest. - Op elke pagina verscheen een tweede Ads-host. Op 19 oktober 2026 liet een nieuwe controle van zes paginatypen zien dat
pagead2.googlesyndication.comoveral laadde. Die stond niet in de trace van juli. Onze eigen beveiligingsscan had gezegd dat het beleid er goed uitzag en dat we de header "gewoon konden hernoemen". Hadden we dat gedaan, dan waren de Ads-conversies naar nul gezakt zonder één zichtbare fout.
Twee kleinere lessen uit hetzelfde werk. Chrome negeert upgrade-insecure-requests in een report-only beleid en logt daar een consolefout over, die Lighthouse dan tegen je telt. Voeg die directive dus pas toe als je overschakelt op afdwingen. En ons framework (SvelteKit) schrijft een inline hydratiescript, terwijl onze hosting alleen vaste headers toestaat. Daarom blijft 'unsafe-inline' voor scripts staan tot we nonces per verzoek toevoegen. Een beleid met een bekend, gedocumenteerd compromis blokkeert nog altijd veel meer dan geen beleid.
Zo rol je een CSP uit zonder iets te breken
- Maak een lijst van wat je pagina's laden. Open de developer tools van de browser, tabblad Network, en klik door de homepage, een contentpagina, de contact- of boekingspagina, de checkout en de bedankpagina. Noteer elke host.
- Schrijf het beleid op basis van die lijst. Begin met
default-src 'self'en voeg elke host toe aan de directive waar hij voor nodig is:script-src,connect-src,img-src,frame-src,style-src,font-src. - Zet het live als report-only, met rapportage. Stuur het als
Content-Security-Policy-Report-Onlymet zowelreport-to(plus eenReporting-Endpoints-header) als het ouderereport-uri. Niet elke browser ondersteuntreport-toal, dus gebruik beide. Log alleen de directive, de geblokkeerde host en het pagina-pad: volledige URL's kunnen bezoekersdata bevatten. - Lees de rapporten een week lang. Echte bezoekers gebruiken andere browsers, extensies, landen en pagina's dan jij. Voeg toe wat van jou of je tools is; negeer ruis van browserextensies.
- Controleer opnieuw na elke tagwijziging. Marketingtools veranderen van host zonder het te zeggen. Loop dezelfde paginatypen opnieuw langs na elke wijziging in de tags of het beleid.
- Schakel over op afdwingen. Hernoem de header naar
Content-Security-Policy, houd de rapportage aan en kijk de volgende dagen naar de rapporten en je conversiecijfers.
| Jouw situatie | Wat je doet |
|---|---|
| Scan zegt "geen CSP", site werkt prima | Begin deze week met report-only; kopieer geen beleid van elders |
| Je hebt een CSP toegevoegd en iets werkt niet meer | Zet de header nu terug naar report-only en herstel het beleid aan de hand van de consolefouten |
| Je draait Google Ads of Meta-advertenties | Test de pagina's waar conversies afgaan en controleer de conversiecijfers een paar dagen na het afdwingen |
| Webshop met een checkout | Test een echte betaling (in testmodus) met het beleid actief; betaal-iframes hebben eigen bronnen nodig |
| WordPress met veel plugins | Reken op een lange lijst; plugins die inline scripts injecteren kunnen voorlopig 'unsafe-inline' afdwingen |
Hulp nodig?
Wij zetten een Content-Security-Policy op de veilige manier op: een trace van je echte pagina's, een report-only fase met logging en de overstap naar afdwingen zodra de rapporten schoon zijn. Je analytics en conversies controleren we ervoor en erna. Stuur ons je websiteadres →
Run je een bureau? Wij doen dit onder jouw naam, onder NDA. Zie hoe we met bureaus werken →
Gerelateerd
Veelgestelde vragen
Wat is Content-Security-Policy-Report-Only?
Een versie van de CSP-header die alleen meldt wat het beleid zou blokkeren, zonder te blokkeren. Browsers sturen de overtredingen naar het rapportadres dat je instelt, zodat je het beleid kunt aanpassen voordat je het afdwingt.
Hoe lang moet een CSP in report-only blijven?
Minstens een week met echt verkeer en geen legitieme bronnen meer in de rapporten. Langer als je site pagina's heeft met weinig bezoekers, zoals een checkout of een bedankpagina.
Moet ik report-to of report-uri gebruiken?
Allebei. report-to is de nieuwere en heeft een Reporting-Endpoints-header nodig. report-uri is verouderd, maar nog nodig omdat report-to nog niet in elke browser werkt.
Kan een CSP de tracking van Google Ads of Analytics breken?
Ja. Ontbreken de hosts waar de tags van laden of waarheen ze data sturen, dan blokkeert de browser ze zonder zichtbare foutmelding. Conversies worden dan gewoon niet meer geteld.
Is een CSP met 'unsafe-inline' nutteloos?
Nee. Het beperkt nog steeds waar scripts, frames en verbindingen vandaan mogen komen en waarheen data mag gaan. 'unsafe-inline' vervangen door nonces is beter, maar een gedocumenteerd compromis is beter dan geen beleid.
Gerelateerde artikelen

SPF-record toegevoegd en Google Search Console kwijt? Dit is waarom
Een SPF-record toevoegen kan je Google-verificatiecode stilletjes wissen uit hetzelfde TXT-record. Zo gebeurde het bij ons, zo check je het en los je het op.


We scanden 1.482 webshops vlak voor Black Friday: dit vonden we
We scanden in oktober 2026 1.482 Shopify- en WooCommerce-shops. De mediaan scoorde 46/100: zware homepages, trage laadtijden, verouderde code en toegankelijkheidsgaten. Wat je als eerste fixt.


Online verkopen in Thailand: webshop, PromptPay en kaartbetalingen (2026)
Zo ontvang je PromptPay- en kaartbetalingen in je eigen webshop in Thailand: aanbieders en kosten vergeleken, wat je nodig hebt en een echte case.

