In de praktijk is de CSP een allowlist die de server met elke pagina meestuurt. De browser leest hem voordat hij iets uitvoert en weigert alles wat er niet op staat: een script van een onbekend domein, een geïnjecteerde stijl, een frame of formulier dat naar elders wijst. Het grootste voordeel is dat hij de schade van een XSS-lek beperkt: ook als een aanvaller code in een pagina weet te krijgen, kan de browser weigeren die uit te voeren.
Hoe een Content Security Policy werkt
Een beleid bestaat uit directives, gescheiden door puntkomma's. Elke directive geldt voor een type bron en somt de toegestane bronnen op:
default-srcis de standaardwaarde voor alle bronnen zonder eigen directive;script-src,style-src,img-src,font-srcgelden voor scripts, stylesheets, afbeeldingen en lettertypen;frame-ancestorsbepaalt welke sites de pagina in een frame mogen tonen, wat beschermt tegen clickjacking;object-src 'none',base-urienform-actionsluiten minder bekende injectieroutes af.
Zodra er een directive script-src of default-src bestaat, worden scripts die direct in de HTML staan en attributen als onclick geblokkeerd. Het sleutelwoord 'unsafe-inline' heft dat verbod op, maar MDN wijst erop dat het een groot deel van het nut van de CSP tenietdoet. De aanbevolen methode, strict CSP genoemd, staat scripts toe via een nonce (een willekeurige waarde die bij elk antwoord anders is en in de <script>-tag wordt herhaald) of via de SHA-256-hash van het script.

Header, meta-tag en report-only-modus
Het beleid verstuur je bij voorkeur in de HTTP-header Content-Security-Policy. Een tag <meta http-equiv> werkt ook, maar de W3C-specificatie zegt dat die frame-ancestors, sandbox en report-uri negeert en geen beleid in report-only-modus kan bevatten.
Die report-only-modus is de sleutel tot een invoering zonder schade. Met Content-Security-Policy-Report-Only verbiedt de browser niets: hij meldt alleen, in de console of naar een adres dat je opgeeft met report-to en de header Reporting-Endpoints, wat hij zou hebben geblokkeerd. Je past de lijst aan en schakelt daarna over op de blokkerende modus.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'nonce-r4nd0m'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
Voor WordPress
WordPress is lastig terrein voor een strict CSP: de core, thema's en veel plugins zetten inline scripts in de pagina. Sinds WordPress 5.7 kun je met de functies wp_get_inline_script_tag(), wp_print_inline_script_tag() en de filter wp_script_attributes een nonce-attribuut toevoegen aan scripts die netjes worden geladen, maar niet aan scripts die een thema hard in de code heeft staan. Daarom beginnen veel sites met 'unsafe-inline' en verscherpen ze het beleid pagina voor pagina.
- Test in report-only-modus de homepage, een bericht, de blokeditor, de formulieren en de betaling.
- Zet het beleid op serverniveau (
.htaccess, Nginx) als een cache pagina's serveert zonder langs PHP te gaan. - Inventariseer de externe domeinen: lettertypen, statistieken, video's, betaalprovider.
Onze gids over beveiligingsheaders voor WordPress geeft een startbeleid en de testmethode, en het artikel over XSS-lekken in WordPress laat zien wat een CSP had kunnen beperken. De CSP hoort bij een bredere familie van HTTP-beveiligingsheaders.
Veelgemaakte fouten
- Een strikt beleid uit een tutorial kopiëren en direct toepassen: de editor of de winkelwagen werkt dan niet meer.
- Dezelfde nonce op meerdere pagina's hergebruiken: hij moet onvoorspelbaar zijn en bij elk antwoord veranderen, wat slecht samengaat met een paginacache.
- Denken dat de CSP het escapen van gegevens vervangt: OWASP ziet hem als defense in depth, niet als de enige bescherming tegen XSS.
WP Masquerade Pro biedt een basis-CSP die browserplugins blokkeert, het base-adres beschermt en bronnen naar HTTPS omzet. Die beperkt bewust geen scripts: een beleid tegen XSS moet je op maat bouwen, in de configuratie van de server of het CDN.