Waarom CSP essentieel is
Content Security Policy is de krachtigste verdedigingslinie tegen cross-site scripting (XSS), de meest voorkomende webkwetsbaarheid ter wereld. CSP werkt als een whitelist: u definieert precies welke bronnen uw website mag laden, en de browser blokkeert al het andere.
Zonder CSP kan een aanvaller die erin slaagt om JavaScript te injecteren vrijwel alles doen: sessies stelen, formulieren manipuleren, malwareverspreiding. Met een goed geconfigureerd CSP wordt geïnjecteerde code geblokkeerd, zelfs als de injectie technisch lukt.
Hoe CSP werkt
CSP werkt via een HTTP-header die de server meestuurt:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
De browser interpreteert dit als: "Laad standaard alleen bronnen van het eigen domein. JavaScript mag alleen komen van het eigen domein en cdn.example.com. Blokkeer al het andere."
De directives
Resource directives
| Directive | Controleert |
|---|---|
| default-src | Fallback voor alle resource-types |
| script-src | JavaScript-bestanden en inline scripts |
| style-src | CSS-bestanden en inline styles |
| img-src | Afbeeldingen |
| font-src | Lettertypes |
| connect-src | AJAX, WebSocket, fetch, EventSource |
| media-src | Audio en video |
| object-src | Plugins (Flash, Java — altijd op 'none' zetten) |
| frame-src | Iframes die geladen mogen worden |
| child-src | Web workers en geneste browsing contexts |
| worker-src | Specifiek voor Web Workers en Service Workers |
| manifest-src | Web app manifesten |
Document directives
| Directive | Controleert |
|---|---|
| base-uri | Beperkt het base element |
| form-action | Beperkt waar formulieren naartoe mogen submitten |
| frame-ancestors | Wie uw pagina in een iframe mag laden (vervangt X-Frame-Options) |
Navigatie directives
| Directive | Controleert |
|---|---|
| navigate-to | Beperkt waar de pagina naartoe mag navigeren |
Source values
| Value | Betekenis |
|---|---|
| 'self' | Eigen domein (zelfde origin) |
| 'none' | Niets toestaan |
| 'unsafe-inline' | Inline scripts/styles toestaan (vermijden!) |
| 'unsafe-eval' | Dynamische code-evaluatie toestaan (vermijden!) |
| 'nonce-{random}' | Specifiek script/style met bijbehorende nonce |
| 'strict-dynamic' | Vertrouwde scripts mogen andere scripts laden |
| https: | Alle HTTPS-bronnen |
| data: | Data-URI's (voor inline afbeeldingen) |
| blob: | Blob-URI's |
| https://example.com | Specifiek domein |
Waarschuwing: 'unsafe-inline' en 'unsafe-eval' ondermijnen de XSS-bescherming van CSP. Gebruik nonces of hashes als alternatief.
Stap-voor-stap implementatie
Stap 1: Begin met Report-Only
Start nooit met een afdwingend CSP. Gebruik eerst de report-only modus:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Dit blokkeert niets maar rapporteert schendingen. Analyseer de reports gedurende minstens een week.
Stap 2: Inventariseer uw bronnen
Maak een lijst van alle externe bronnen die uw website laadt:
- CDN's voor JavaScript-libraries
- Google Fonts of andere lettertypediensten
- Analytics (Google Analytics, Plausible)
- Social media widgets
- Advertentienetwerken
- Betaaldiensten (Mollie, Stripe)
- Chatwidgets
Stap 3: Bouw uw policy op
Begin streng en verruim waar nodig:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'nonce-{random}';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
Stap 4: Gebruik nonces in plaats van unsafe-inline
Inline scripts en styles worden standaard geblokkeerd door CSP. Gebruik nonces om specifieke inline elementen toe te staan:
<!-- Server genereert unieke nonce per request -->
<script nonce="a1b2c3d4e5f6">
// Dit script wordt toegestaan
</script>
Content-Security-Policy: script-src 'nonce-a1b2c3d4e5f6'
Stap 5: Test en verfijn
- Controleer de website-functionaliteit na elke wijziging
- Monitor CSP-reports op onverwachte blokkades
- Verfijn het beleid totdat alles correct werkt
- Schakel over van Report-Only naar afdwingend
CSP voor veelgebruikte diensten
Google Analytics (GA4)
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
img-src 'self' https://www.google-analytics.com;
connect-src 'self' https://www.google-analytics.com https://analytics.google.com;
Google Fonts
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
Mollie (betalingen)
script-src 'self' https://js.mollie.com;
frame-src https://js.mollie.com;
YouTube embeds
frame-src https://www.youtube-nocookie.com;
Veelgemaakte fouten
| Fout | Risico |
|---|---|
| default-src * | CSP is effectief uitgeschakeld |
| script-src met unsafe waarden | XSS-bescherming ongedaan gemaakt |
| CSP alleen op homepage | Andere pagina's onbeschermd |
| Geen object-src 'none' | Plugin-gebaseerde aanvallen mogelijk |
| Geen frame-ancestors | Clickjacking nog steeds mogelijk |
| Te veel domeinen in whitelist | Aanvalsoppervlak vergroot |
CSP Level 3: strict-dynamic
Voor complexe applicaties met veel third-party scripts biedt strict-dynamic een pragmatische aanpak:
Content-Security-Policy: script-src 'nonce-{random}' 'strict-dynamic' https:;
Met strict-dynamic mogen scripts die geladen worden door een vertrouwd script (met geldige nonce) zelf ook weer scripts laden. Dit vereenvoudigt het beheer van complexe dependency-ketens.
Monitoring en onderhoud
CSP is geen set-and-forget oplossing. Onderhoud uw beleid:
- Monitor reports doorlopend op nieuwe schendingen
- Pas het beleid aan wanneer u nieuwe diensten integreert
- Verwijder bronnen die u niet meer gebruikt
- Controleer periodiek of de whitelisted domeinen nog betrouwbaar zijn
Scan uw website gratis met WarDek — OWASP, NIS2, AVG, AI Act compliance in één scan.