Content-Security-Policy (CSP) is een van de krachtigste beveiligingsmechanismen voor je website. Het vertelt de browser precies welke bronnen wel en niet geladen mogen worden. Maar het is ook een van de meest verwarrende headers om correct in te stellen. In dit artikel leggen we CSP helder uit, zodat je het met vertrouwen kunt implementeren.
Wat is Content-Security-Policy?
CSP is een HTTP-header die je server meestuurt met elke pagina. Het werkt als een whitelist: je vertelt de browser precies welke bronnen (scripts, stylesheets, afbeeldingen, fonts, etc.) geladen mogen worden en vanaf welke domeinen.
Alles wat niet op de whitelist staat, wordt geblokkeerd. Dit is je belangrijkste verdediging tegen Cross-Site Scripting (XSS) aanvallen, waarbij aanvallers kwaadaardig JavaScript in je pagina proberen te injecteren.
Hoe werkt CSP in de praktijk?
Een CSP-header bestaat uit een reeks directives. Elke directive bepaalt het beleid voor een specifiek type bron:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
Laten we dit ontleden:
default-src 'self'- Standaard mogen alleen bronnen van je eigen domein geladen wordenscript-src 'self' https://cdn.example.com- Scripts mogen alleen van je eigen domein en cdn.example.com komenstyle-src 'self' 'unsafe-inline'- Stylesheets van je eigen domein, plus inline styles zijn toegestaanimg-src 'self' data: https:- Afbeeldingen van je eigen domein, data-URLs en elke HTTPS-bron
Wat betekent 'unsafe-inline'?
'unsafe-inline' staat toe dat inline code (zoals <script>alert('hi')</script> of style="color: red") wordt uitgevoerd. Het woord "unsafe" zit er niet voor niets in: het verzwakt je CSP aanzienlijk.
Waarom is het gevaarlijk? Als een aanvaller HTML kan injecteren in je pagina (via een formulier, URL of database), kan die ook inline scripts toevoegen. Met 'unsafe-inline' worden die scripts gewoon uitgevoerd.
Hoe vermijd je het? Gebruik in plaats van inline scripts en styles aparte bestanden. Als dat niet mogelijk is (bijvoorbeeld bij CSS-in-JS frameworks), gebruik dan een nonce of hash:
// Met een nonce (eenmalig token per request)
Content-Security-Policy: script-src 'nonce-abc123def456'
// In je HTML
<script nonce="abc123def456">
// Dit script wordt uitgevoerd
</script>
<script>
// Dit script wordt GEBLOKKEERD (geen nonce)
</script>