Content Security Policy
Een Content Security Policy (CSP) is een browserbeveiligingsstandaard gedefinieerd door het World Wide Web Consortium (W3C). Het helpt ontwikkelaars websites te beschermen tegen client-side aanvallen zoals cross-site scripting (XSS) en data-injectie. Door vertrouwde bronnen voor scripts, stijlen en media te specificeren, fungeert een CSP als een whitelist die browsers automatisch afdwingen als onderdeel van het client-side beveiligingsmodel.
Samenvatting (TL;DR)
- CSP definieert welke bronnen een browser kan vertrouwen.
- Het helpt geïnjecteerde of ongeautoriseerde scripts te blokkeren.
- Het vermindert risico’s op XSS en data-exfiltratie.
- Werkt het beste in combinatie met inputvalidatie en HTTPS.
- Vereist doorlopend onderhoud en testen.
Content Security Policy (CSP) begrijpen
Content Security Policy (CSP) is een browserbeveiligingsfunctie die is geïmplementeerd om bepaalde soorten browseraanvallen te beperken, zoals cross-site scripting. De CSP is gestandaardiseerd door het World Wide Web Consortium (W3C) in de CSP Level 3 specificatie. Het stelt een website in staat om een set regels te sturen (via HTTP-response headers of tags in de HTML ) die de browser instrueren welke contentbronnen zijn toegestaan.
Deze regels, genaamd directives, specificeren goedgekeurde origins voor scripts, afbeeldingen, stijlen, iframes en meer. Het primaire doel van CSP is volledige controle te hebben over waar scripts vandaan worden geladen, samen met controle over welke scripts een pagina mag uitvoeren, om zo geïnjecteerde of ongeautoriseerde scripts te blokkeren.
Bijvoorbeeld, een CSP-directive kan aangeven dat scripts alleen mogen laden vanaf het eigen domein (met ‘self’), of van specifieke vertrouwde domeinen. De browser blokkeert dan elk scriptbestand of inline script dat niet van een toegestane bron komt, wat een cruciale verdediging biedt tegen XSS-aanvallen waarbij een aanvaller kwaadaardige
Hoe Content Security Policy (CSP) werkt
Een Content Security Policy wordt aan een browser geleverd via de HTTP-response header genaamd Content-Security-Policy, of via een meta tag in de HTML . De policy bestaat uit directives gescheiden door puntkomma’s, en elke directive controleert een specifiek type bron.
- ‘script-src’ self: staat alleen scripts toe van dezelfde origin. Elk
- ‘connect-src’ self https://api.domain.com : staat AJAX/XHR/fetch-aanroepen alleen toe naar dezelfde site of naar het vertrouwde domein api.domain.com. Dit voorkomt dat kwaadaardige code data exfiltreert naar onbekende servers.
- img-src ‘self’ data: kan worden gebruikt om alleen afbeeldingen van dezelfde site te laden en externe afbeeldingen te blokkeren - wat kan worden gebruikt om datalekken via afbeeldingsverzoeken te voorkomen.
CSP Nonces en CSP Hashes
CSP ondersteunt ook geavanceerde mechanismen zoals nonces (‘nonce-abc123’) en hashes (‘sha256-xyz…’). Deze stellen inline scripts in staat veilig uit te voeren door cryptografisch hun integriteit te bewijzen. In plaats van alle inline code te verbieden, kunnen ontwikkelaars selectief specifieke scripts autoriseren, wat flexibiliteit verbetert zonder beveiliging op te offeren.
Er zijn talloze andere directives die kunnen worden gebruikt voor andere datatypen zoals media, fonts, iframes, etc., maar de kerngedachte van een Content Security Policy is het whitelisten van vertrouwde bronnen. Wanneer de browser een pagina laadt en vraagt welke content te laden, raadpleegt deze eerst de CSP en dwingt deze regels af bij elke laadactie. Elk script of bron die niet voldoet aan deze policy wordt niet geladen. Voor een gedetailleerde implementatiegids, bekijk de OWASP CSP Cheat Sheet.
Veelvoorkomende CSP-directives en hun doel
| Directive | Doel | Typisch gebruik |
|---|---|---|
default-src | Stelt een basisbeleid in voor alle bronnen wanneer geen andere regel van toepassing is. | Begin strikt: default-src 'none'; |
script-src | Bepaalt welke JavaScript-bronnen zijn toegestaan. | Whitelist 'self', CDN’s, of gebruik nonce/hash-gebaseerde scripts. |
style-src | Beperkt waar CSS vandaan mag laden. | Gebruik 'self'; vermijd 'unsafe-inline' waar mogelijk. |
img-src | Definieert vertrouwde afbeeldingsbronnen. | Voorkom datalekken via externe afbeeldingsaanroepen. |
connect-src | Beperkt AJAX-, fetch- en WebSocket-bestemmingen. | Blokkeer data-exfiltratie naar onbekende domeinen. |
frame-ancestors | Specificeert welke sites je pagina’s mogen embedden in iframes. | Voorkom clickjacking: frame-ancestors 'none'; |
report-uri / report-to | Definieert waar CSP-overtredingsrapporten naartoe worden gestuurd. | Log en analyseer CSP-schendingen voor policy-afstemming. |
Hoe een CSP een website kan beschermen
Beperking van XSS-aanvallen: Bij een cross-site scripting aanval, of XSS-aanval, vindt een aanvaller over het algemeen een manier om kwaadaardige JavaScript-code in je pagina te injecteren en uit te voeren (zoals op een niet-gesaniteerde input). Standaard blokkeert een CSP alle inline scripts op de pagina, tenzij een policy-directive dit expliciet toestaat. Dit betekent dat als een aanvaller iets als <script>evilCode()</script> in een pagina injecteert, dit niet wordt uitgevoerd (tenzij ‘unsafe-inline’ is toegestaan in de CSP!)
Blokkeren van ongeautoriseerde third-party scripts: Veel sites hebben third-party scripts voor zaken als analytics, gebruikerstracking en advertenties. Met een CSP kunnen site-eigenaren beperken welke externe sites daadwerkelijk scripts mogen leveren. Bijvoorbeeld, als je alleen content wilt serveren van analytics.example.com en niets anders van example.com, kan de script-src directive van je site’s CSP expliciet alleen dat toestaan.
Voorkomen van data-exfiltratie: Zoals eerder genoemd, kan een CSP acties op een pagina beperken die kunnen worden gebruikt om kwaadaardige JavaScript-code te stoppen van het terugsturen van data naar een door een aanvaller gecontroleerd domein. Het gebruik van de connect-src directive blokkeert netwerkverzoeken naar ongeautoriseerde servers, en kan worden gecombineerd met de form-action directive om te verzekeren dat data alleen naar jouw domein wordt gestuurd.
Afdwingen van veilige browserpraktijken: Een CSP heeft directives om veilig gedrag af te dwingen dat de beveiliging van je site in het algemeen verbetert. Een voorbeeld hiervan is upgrade-insecure-requests, die de browser dwingt alle bronnen via HTTPS te laden, waardoor gemengde en onveilige content wordt voorkomen. Een andere directive is frame-ancestors, die clickjacking-aanvallen kan voorkomen door niet toe te staan dat je pagina wordt geëmbed in een door een aanvaller gecontroleerd frame.
Hoe CSP browsergebaseerde aanvallen voorkomt
1. Beperking van XSS-aanvallen:
Bij een cross-site scripting aanval, of XSS-aanval, vindt een aanvaller over het algemeen een manier om kwaadaardige JavaScript-code in je pagina te injecteren en uit te voeren (zoals op een niet-gesaniteerde input). Standaard blokkeert een CSP alle inline scripts op de pagina, tenzij een policy-directive dit expliciet toestaat. Dit betekent dat als een aanvaller iets als <script>evilCode()</script> in een pagina injecteert, dit niet wordt uitgevoerd (tenzij ‘unsafe-inline’ is toegestaan in de CSP!)
2. Blokkeren van ongeautoriseerde third-party scripts:
Veel sites hebben third-party scripts voor zaken als analytics, gebruikerstracking en advertenties. Met een CSP kunnen site-eigenaren beperken welke externe sites daadwerkelijk scripts mogen leveren. Bijvoorbeeld, als je alleen content wilt serveren van analytics.example.com en niets anders van example.com, kan de script-src directive van je site’s CSP expliciet alleen dat toestaan.
3. Voorkomen van data-exfiltratie:
Zoals eerder genoemd, kan een CSP acties op een pagina beperken die kunnen worden gebruikt om kwaadaardige JavaScript-code te stoppen van het terugsturen van data naar een door een aanvaller gecontroleerd domein. Het gebruik van de connect-src directive blokkeert netwerkverzoeken naar ongeautoriseerde servers, en kan worden gecombineerd met de form-action directive om te verzekeren dat data alleen naar jouw domein wordt gestuurd.
4. Afdwingen van veilige browserpraktijken:
Een CSP heeft directives om veilig gedrag af te dwingen dat de beveiliging van je site in het algemeen verbetert.
- Een voorbeeld hiervan is
upgrade-insecure-requests, die de browser dwingt alle bronnen via HTTPS te laden, waardoor gemengde en onveilige content wordt voorkomen. - Een andere directive is
frame-ancestors, die clickjacking-aanvallen kan voorkomen door niet toe te staan dat je pagina wordt geëmbed in een door een aanvaller gecontroleerd frame.
Gecombineerd resulteren deze policies in een robuuste client-side basis voor moderne webapplicaties.
Beveiligingsbeperkingen van CSP
Het gebruik van een Content Security Policy biedt sterke bescherming, maar is geen allesomvattende oplossing voor je site, zoals belicht in ons artikel “Waarom Content Security Policy niet werkt”.
Policies kunnen na verloop van tijd afdrijven, en allowlists inspecteren geen codegedrag. Elke grote browser implementeert CSP op zijn eigen, licht verschillende manier. Chrome, Firefox, Safari en Edge ondersteunen allemaal CSP Level 3; rapportagegedrag en overtredingsformaten kunnen variëren. Om je policy te valideren en te onderhouden, test deze regelmatig met browser developer tools en geautomatiseerde scanners zoals Mozilla Observatory of SecurityHeaders.io.
Het combineren van een CSP met een actieve client-side proxy zoals cside om real-time inspectie en blokkering toe te voegen aan third-party scripts op je site geeft je een uitstekende verdedigingslaag, met gemoedsrust voor je klanten. Vanuit governance-perspectief verbetert het documenteren van CSP-updates en monitoren van overtredingsrapporten de controleerbaarheid en langetermijn-compliance met frameworks zoals ISO 27001 en OWASP ASVS.
Werkt CSP voor PCI DSS 6.4.3 compliance?
Onder PCI DSS 4.0.1 Vereiste 6.4.3 moeten merchants bewijzen dat elk client-side script is geautoriseerd en de script-integriteit aantonen. CSP en SRI brengen je een deel van de weg. CSP beperkt welke domeinen scripts mogen laden, en SRI controleert of de code van een bestand niet is veranderd. Maar samen zijn ze een statische oplossing voor een dynamisch probleem. Dynamische scripts updaten en hashes breken. Handmatig onderhoud van CSP-lijsten is vrijwel onmogelijk.
De meeste moderne sites gebruiken dynamische third-party scripts, dus deze controles verslechteren snel. Deze aanpak zal doorgaans tekortschieten in het vereiste bewijs voor PCI 6.4.3.
Een voorbeeld van een verkeerd geconfigureerde CSP
De dag dat de checkout stopte: hoe een strikte CSP productie brak
Het begon allemaal met een gewone nieuwe deployment. Niets bijzonders, gewoon een nieuwe Content Security Policy om een eCommerce shop veiliger te maken en aanvallers te blokkeren van het insluipen van kwaadaardige code.
De schone default-src ‘none’ was ingesteld zonder testen. En dus, het moment dat de CSP werd geactiveerd, blokkeerde de website diensten die het eigenlijk nodig had. Analytics stopte met werken en het ergste van alles, het betalingssysteem werd geblokkeerd. Klanten konden hun bestellingen niet afronden en het checkout-systeem brak. Ontwikkelaars gingen aan het werk en schakelden de header om naar Content-Security-Policy-Report-Only en verzamelden overtredingslogs. Van daaruit bouwden ze een allowlist (script-src ‘self’ https://pay.examplecase.com) met alle diensten die de webshop nodig had om goed te functioneren.
Het verfijnen van de CSP maakte deployment mogelijk zonder problemen. Helaas is deze vergissing een veelvoorkomend ongeluk wanneer teams CSP intern beheren. Het vergeten om een nieuw marketingscript te whitelisten, technische misconfiguraties, of problemen met dynamische scripts die hashingprotocollen breken maken CSP een nachtmerrie om op schaal te beheren.