Implementatie van Content Security Policy voor websites

02 feb. 2019

Websitebeveiliging is de laatste jaren een steeds belangrijker geworden, maar zelfs met deze toenemende focus op beveiliging zijn veel websites nog steeds kwetsbaar voor eenvoudig op te lossen kwetsbaarheden. Een van de kwetsbaarheden waar veel, zowel kleine als grote sites, nog steeds vatbaar voor zijn is Cross Site Scripting (XSS). Volgens OWASP zijn XSS-problemen te vinden in ongeveer twee derde van alle websites (zie OWASP top 10-2017, A7: 2017). Het gebruik van moderne ontwikkel frameworks en de juiste veilige ontwikkelmethodes en richtlijnen kunnen een groot deel van de kwetsbaarheden oplossen maar voor veel oudere applicaties zal dit moeilijk zo niet onmogelijk zijn. Het implementeren van een Content Security Policy is een relatief eenvoudige manier om vele vormen van XSS-kwetsbaarheden voor zowel oude als moderne websites te voorkomen. Voor verouderde websites kan Content Security Policy de enige haalbare XSS-preventietechniek zijn, voor modernere sites kan het fungeren als een extra verdedigingslinie die de preventietechnieken aanvult die zijn toegepast tijdens ontwikkeling.

Wat is Content Security Policy

Content Security Policy (meestal afgekort tot CSP) is eigenlijk een set van regels (policies) waarin staat beschreven welke website bronnen er van welke domeinen toegestaan worden. Deze regels voeg je toe aan een CSP antwoord header die je toevoegt aan je website. Als een browser die CSP ondersteund deze header detecteert zorgt deze browser ervoor dat de regels die je in de antwoord header mee hebt gegeven worden gehandhaafd.

Een eenvoudig functioneel voorbeeld van een CSP regel kan zijn : externe scripts bronnen mogen alleen afkomstig zijn van mijn eigen domein of van google.com

Met CSP kan je regels instellen voor de volgende bronnen:

  • scripts
  • stylesheets
  • images
  • objects
  • media (video en audio)
  • fonts
  • iframes
  • workers

De regels voor al deze bron types wordt vastgelegd in directives. Voor alle directives kan je een of meer toegestane domeinen toevoegen. Met de juiste set van toegestane domeinen kan je voorkomen dat er bronnen (vooral Javascript) wordt gebruikt van niet vertrouwde domeinen. Hierdoor wordt het risico dat een aanvaller onveilige bronnen injecteert weggenomen of in ieder geval verminderd.

Naast het toestaan van domeinen zijn er nog een aantal extra regels in te stellen. De meest belangrijke hiervan is of inline Javascript en Stylesheets zijn toegestaan. Standaard staat CSP inline Javascript en Stylesheets niet toe, je moet het expliciet aanzetten om het te laten blijven werken op je website. Het blokkeren van vooral inline javascript voorkomt veel vormen van XSS kwetsbaarheden op websites, dus als het mogelijk is om inline Javascript uit te laten staan is dit zeer aan te raden. Als je er niet onderuit komt om inline Javascript toch toe te staan dan zijn er nog opties om alleen bepaalde inline scripts toe te staan, deze scripts kan je dan identificeren aan de hand van een hash of een nonce (number used once) welke je toevoegt aan zowel je script tags als in je CSP directives.

Dit blog is niet bedoeld om diep in te gaan om alle details van de verschillende CSP directives, voor deze details kan je bijvoorbeeld kijken op het Mozilla Developers Network.


Examples

Example 1

The following example is the most basic implementation. The value 'self' means only the same domain (as the website which set the header) is allowed. The default-src directive is used to define a default policy and is used as fallback for all directives which are not explicitly set.

Content-Security-Policy: default-src 'self';

Example 2

This example allows images to be included from all domains, media (video and audio) only from media1.com and media2.com and scripts only from the same domain as your site and from the domain userscripts.example.com. All other sources (like stylesheets and fonts) are not explicitly set, so they fallback to the default-src directive which is set to 'self'.

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src 'self' userscripts.example.com

Example 3

The last example again allows only media from the domains media1.com and media2.com. Images are only allowed from site using HTTPS. Scripts are set to be allowed from the same domain and inline scripts are explicitly allowed by setting 'unsafe-inline'.

Content-Security-Policy: default-src 'self'; img-src https: ; media-src media1.com media2.com; script-src 'self' 'unsafe-inline'

Points of concern

Adding a CSP to your website is not a magical solution to your XSS (and some other) security vulnerabilities. There are some things you have to take into account before you begin implementing it.

Browser support

Not all browsers support CSP, most notably Internet Explorer. And some browsers have limited CSP support. So if you are unlucky enough to have a lot of users visiting your website with older browsers, look very carefully which CSP directives you can actual implement. See Can I Use CSP for the latest browser support.

There are multiple versions of CSP

The current version (at the time of writing) is CSP 2.0, but older browsers only support version 1.0. The upcoming 3.0 version will have some possible breaking changes. So look carefully at what CSP versions your clients will support. Some of the bigger changes between CSP 2.0 and 3.0 are:

  • frame-src directive which was deprecated in CSP 2.0 is un-deprecated in CSP 3.0
  • report-uri directive has been renamed to report-to

See W3C documentation CSP 3 for all changes from version 2.0 to 3.0. And W3C documentation CSP 2 for changes from level 1.0 to 2.0.

Users can switch CSP off in their browser

Because CSP is a security feature implemented by browsers, you have no actual control if users actual use it. With browser extensions a user could disable CSP in their browser. If they do, it is basically at their own risk but just keep in mind that the fact that all your users have browsers which support CSP does not mean that those users are actually protected by their browsers CSP feature.

Implementation steps

Implementing a proper CSP for your site is not trivial, especially for larger sites. The followings steps will help smoothen your implementation.

1. Find out what resources your website uses

Before you can create a policy to whitelist certain resources you will first have to determine which resources your website is actually using. There are a couple of approaches.

  • Open the most important pages in your site in a browser and use your browsers developer tools to inspect all resources used by the page you are viewing.
  • Dive into the source code of your website and try to determine which resources are included
  • Ask your most experienced developers to get you a list of what resources they can think of

Pay extra attention to any analytics tools your site uses, some of those tools inject javascript in your site which does it's own calls to external resources. Those resources won't be found in your source code. Using one or more of those approaches will give you a list of all resources you need to include in your initial policy to ensure your website won't stop working when you implement the policy.

2. Create an initial policy

Once you have a decent list of resources, you can start creating your first CSP rules by extracting all the unique domains from your list of resources and mapping them to the CSP directives (like script-src, style-src and so on).

3. Document your policy rules

The third step is meant to make sure you and your organisation can see which CSP rules are in place, why they are necessary and when and by who they are approved. Your documentation could for example hold a list of allowed domains, a description of what they are used for and a date of when they are approved.

4. Release your policy to production in report-only mode

Once your initial CSP rules are defined and documented you can implement them in your website in report-only mode. In report-only mode every time your production website violates any CSP rule a report is send to a report url you supply. You do this by using the header Content-Security-Policy-Report-Only in stead of Content-Security-Policy and adding the report-uri directive with a valid url which can receive the violation reports.

Content-Security-Policy-Report-Only: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com report-uri http://your-report-uri.com

You can host your own application for receiving the violation reports but an easy alternative is using a commercial CSP report handling solution like Report Uri.

5. Review the policy violation reports

Once your CSP violations are properly collected you wil have to start analysing them. Allow some time to collect enough reports before analysing. Browsing through all violations will most likely reveal some unexpected calls from your website to external resources. Check out if those calls are necessary and if so document them (see step 3).

6. Tweak your policy

With the result of your violation report review (step 5) you can update your CSP rules, allowing extra domains where necessary.

7. Repeat steps 4 to 6

Depending on how many violations are found in step 5 you can do another review cycle (steps 4 - 6).

8. Introduce and enforce procedures for updating your policy

You now have a proper set of CSP rules and a documented list of why those rules are necessary. Now you have to make sure that any future change to your rules is done according to a clear procedure. Not just any developer who needs to use an external resource should be able to update the CSP rules. A way of working could be to only allow changes to the actual CSP rules when those changes are listed and approved in your documented list (see step 3).

9. Introduce and enforce scheduled manual validation actions

To make sure your documented list keeps representing the actual CSP implementation on your website it is advisable to introduce scheduled checks. You could introduce a quarterly validation actions for development teams to validate if all rules in the documented list are properly implemented. If you do so, make sure you document all validation actions with their date and results. This will supply proof to your organisation that the CSP rules are really kept up to date.

10. Implement automated validations

As an extra validation you can add automated validations. A good option would be to run an CSP validation tool during your build and deploy process. A few available tools at the moment of writing are:

11. Release your policy in enforce mode

At this point you are finally ready to release your CSP to production in enforce mode, this means you remove the report-only from your CSP header and your rules will be enforced from now on. You can still leave the report-uri directive in your CSP header if you wish. All violations of your CSP rules will still be reported in that case. If you do a future update to your CSP you can also have both a report-only and an enforce CSP header at the same time. They can even both report violations to different uri's.

Content-Security-Policy: default-src 'self'; script-src userscripts.example.com report-uri http://your-current-report-uri.com

Content-Security-Policy-Report-Only: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com report-uri http://your-new-report-uri.com

12. Keep monitoring violations of your policy

As mentioned in the previous step you can keep reporting all CSP violations even for an enforced CSP. If you choose to do this, make sure that you keep monitoring your violation reports periodically. You could include an analysis of the violation reports in the periodical validation actions (step 9).

Conclusion

By adding proper CSP rules to your website you can reduce a great number of possible security vulnerabilities. Al lot of XSS vulnerabilities can be mitigated this way. Implementation can be difficult for larger websites but by following the suggested steps your implementation will be made easier, safer and more controlled. As an added bonus you will have the right controls in place to keep your CSP in sync with the (security) requirements of your organisation.