Kenneth Linzey

CSP — het hoe en waarom van een Content Security Policy

De afgelopen tijd stellen wij steeds meer van onze klanten voor om naast de gebruikelijke security headers nu ook een Content Security Policy (CSP) in te stellen. In deze blog gaan wij hier dieper op in: waar komt deze nieuwe standaard vandaan? Waarom zou je deze graag willen gebruiken? Hoe stel je deze in? En: met welke andere standaarden heeft CSP raakvlakken?

Waar komt deze nieuwe standaard vandaan en waarom willen we die gebruiken?

CSP is ontwikkeld door het World Wide Web Consortium (W3C), de internationale standaardenorganisatie voor het web. CSP is een nieuwe standaard die webdevelopers in staat stelt om beperkingen te definiëren op het gedrag van de website of ‑applicatie. Bijvoorbeeld: vanaf welke externe locaties worden scripts, stylesheets of images ingeladen? Mag de browser de site in een frame van een andere site inladen?

Een goed afgestelde CSP kan op die manier diverse aanvallen en kwetsbaarheden zoals cross-site scripting (XSS), clickjacking en andere soorten aanvallen voorkomen.

Hoe stel je een CSP in?

Webservers kunnen in antwoord op elk verzoek een speciale header meesturen met de naam Content-Security-Policy. Deze site geeft bijvoorbeeld het volgende:

Content-Security-Policy: default-src https://hackdefense.nl https://hackdefense.com; script-src 'none'; frame-ancestors 'none'; block-all-mixed-content; report-uri /csp-violations/;

Wat betekenen de attributen?

In een CSP header kunnen vele attributen gedefinieerd worden. Kijk hier voor een volledig en actueel overzicht. We lichten de belangrijkste er uit:

  • default-src: hierop wordt teruggevallen wanneer er door de andere attributen niets gedefinieerd is. De waarde van dit attribuut is vaak self om aan te geven dat resources alleen vanaf de eigen site worden ingeladen.
  • script-src: beperkt de locaties van waar een extern script mag worden ingeladen. Gebruikt de site geen client side scripts dan kan dat met de waarde none worden aangegeven.
  • img-src: beperkt de locaties van waar afbeeldingen mogen worden ingeladen.
  • media-src: beperkt de locaties van waar media, bijvoorbeeld video’s, mogen worden ingeladen.
  • object-src: beperkt de locaties van waar plugins mogen worden ingeladen.
  • manifest-src: beperkt de locaties van waar de applicatie manifest mag worden ingeladen. 
  • frame-ancestors: dit attribuut beperkt de locaties die de webpagina mogen inladen middels frame-, iframe-, object-, embed- of applet-elementen. frame-ancestors moet op den duur de HTTP response header X-Frame-Options gaan vervangen.
  • form-action: beperkt de URL’s die gebruikt mogen worden als actie van <form>-elementen. Met andere woorden, hiermee wordt gelimiteerd waar de browser ingevulde formulierdata heen kan sturen. Let op dat dit attribuut niet wordt gedekt met default-src, dus dat dit apart moet worden gespecificeerd als uw site of applicatie form-elementen bevat.
  • Plugin-types: helpt bij het beperken van de set plug-ins die mogen worden ingebed door geldige Mime types te definiëren welke worden aangeroepen via object , embed of applet elementen. 
  • Base-uri helpt bij het beperken van de toegestane URL’s in de src attribuut van een base tag.

Ook kan men CSP gebruiken om af te dwingen dat resources altijd over HTTPS worden ingeladen door aan elke *-src-attribuut in de waarde ook het protocol https: mee te geven. Dit voorkomt dat resources over niet-versleutelde HTTP-verbindingen worden ingeladen. Dit kan ook worden bereikt met het attribuut block-all-mixed-content.

CSP beperkt daarnaast standaard een aantal slechte gebruiken:

  • Ongesigneerde inline Javascript code in <script>-blokken.
  • Ongesigneerde inline CSS statements in <style>-blokken.
  • Dynamische Javascript code-evaluatie met eval().
  • Dynamische CSS statements met de CSSStyleSheet.insertRule()-methode.

Dit sluit aan op de best practice om scripts en CSS in aparte bestanden te houden waarnaar de pagina’s verwijzen. Als dit toch in de site wordt gebruikt kan dit wel in de CSP worden aangegeven met keywords als unsafe-inline en unsafe-eval.

Hoe stel je een CSP in?

De CSP kan op een aantal plekken op een web server gedefinieerd worden, onder andere in de configuratie van de desbetreffende webserver of middels PHP. We raden aan om eerst gebruik te maken van de Content-Security-Policy-Report-Only header. Deze header blokt geen overtredingen, maar rapporteert ze wel. Dit stelt je in staat om de header te definiëren, rustig de website te browsen en overtredingen van de CSP op te pakken, zonder dat dit de functionaliteit van de website beïnvloedt. De volgende header zou als uitgangspunt gebruikt kunnen worden:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri website.nl/api/post/csp-violations;

Elke keer wanneer een opgevraagde resource de CSP overtreedt, maakt de browser een POST request naar de URL gespecificeerd met de report-uri van de CSP met daarbij details over de overtreding. Het is belangrijk om toezicht te houden op deze meldingen. Enerzijds wil je weten wanneer de CSP onnodig resources blokkeert. Anderzijds wil je weten wanneer een resource door iemand anders wordt geïnjecteerd in jouw website, wellicht een aanvaller of kwaadaardige gebruiker.

Als je al een goed beeld hebt van hoe jouw CSP er uit moet komen te zien, is het ook mogelijk om er één te genereren middels deze website.

In CSP level 3 wordt de report-uri functionaliteit vervangen door report-to, maar report-to wordt alleen nog in de browsers Chrome en Microsoft Edge ondersteund. Wij raden aan om zowel report-uri als report-to op te nemen in de CSP.

Met welke andere standaarden heeft CSP raakvlakken?

SubResource Integrity (SRI) is een standaard complementair aan CSP. SRI zorgt ervoor dat alleen bekende en vertrouwde resources van third-party-providers worden ingeladen. Steeds meer browsers beginnen SRI te ondersteunen. Het werkt als volgt:

  • Men rekent een hash uit van de third-party-resource die men op de web pagina wil gebruiken. Er kan bijvoorbeeld gebruik gemaakt worden van een online calculator of men voert het volgende commando uit in een Linux-/UNIX-terminal:
openssl dgst -sha256 -binary FILENAME | openssl base64 -A
  • Vervolgens voegt men een extra attribuut toe aan de third-party-resource die men inlaadt op de webpagina genaamd integrity. De waarde van dit veld is de hash die men in de eerste stap heeft ingeladen, voorafgegaan door de naam van de hashmethode. Voorbeeld:
<script src="https://code.jquery.com/jquery-1.10.2.min.js" integrity="sha256-C6CB9UYIS9UJeqinPHWTHVqh/E1uhG5Twh+Y5qFQmYg=" crossorigin="anonymous"></script>
  • Als de third party resource nu plotseling verandert, dan wordt deze niet meer ingeladen door de browser, omdat de hash niet meer overeenkomt.

In de CSP kan het gebruik van SRI worden afgedwongen met het attribuut require-sri-for en de waarden script of style.

Heeft u nog vragen of heeft u technische ondersteuning nodig bij het beveiligen van uw website of ‑applicatie met een Content Security Policy? Online vindt u meer informatie op content​-security​-policy​.com of u kunt altijd contact met ons opnemen — we helpen u graag verder.