Content Security Policies

Warning: This post is over a year old. The information may be out of date.

A Content Security Policy (CSP) is a way to help prevent cross-site scripting (XSS) and related attacks via the use of a HTTP header that allows you to declare the approved sources of content on a web-page.

This post isn’t going to be a massively in-depth list of all the possible ways it can be used and all the options, there’s links at the end for resources that contain great information about CSPs.

Until last year, I’d not heard of a CSP, or what it does / why I’d need it.

Then, in October, Mark Goodwin (@mr_goodwin) came to PHP East Midlands (@PHPEM) and gave a talk on it. Minds were blown. “everything should use this, why am I not using this already?!”

Currently, content on my site is fairly simple, everything loads from this domain with the exception of some Google analytics code. Because of this, I want to limit browsers from loading content that’s not from a pre-approved list of providers to stop naughty people doing naughty things.

The content-security-policy I’m currently using is:

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' www.google-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: www.google-analytics.com

You can see it if you inspect the headers on the response from any page.

What this allows is:

  1. Scripts, styles and images to be loaded from my domain
  2. Scripts and images to be loaded from www.google-analytics.com for the analytics code that needs to be run
  3. Inline scripts and styles
  4. Eval of scripts and styles
  5. Images to load from a Data URI.
  6. The default fallback for anything that isn’t matched above is to only load it if it’s come from ‘self’ (this website)

Anything that violates this won’t be loaded by the browser. Meaning it’s another way to protect your site from XSS attacks.

A few of these I’d like to remove / change (namely the ‘unsafe-inline’ options as they make things less secure) but currently they’re required for the CMS of the site which is a bit unfortunate. CKEditor won’t load without an 'unsafe-eval' option. I’ve switched to using Markdown instead but ckeditor was still trying to load and causing some browser issues along the way. Ugh, hassle.

This isn’t ideal, and in some ways doesn’t actually make anything stronger, but I’m using this as an exercise to make myself think more about security and keep things fresh in my mind.

But how can I test this without breaking my site?

There’s a simple answer!

Content-Security-Policy-Report-Only: policy

What this does, is look at the security policy provided and report what would have been blocked, but does not enforce it. This means you can add new things to your policy in advance without breaking the old one. Then, once tested, you can implement the new policy knowing that it won’t suddenly break your site as you’ve tested it before with the reporting option.

If I were to add Disqus comments, or some other code / features that required content to be loaded from a different domain, I’d be able to setup the new policy as a report only policy, test it, then once I’m confident it’s working I could make it the real policy that’s enforced by the browser.

This just a brief post on it and what I’m using, there’s lots of resources out there that detail features in more depth.

So, I have to trust browsers to implement this?

Yes, this is all in-browser and not all browsers support this, this website has a list of support.

When I was writing and testing the security policy for the site, the whole time I was thinking about what I should and shouldn’t allow, for what I’m doing here. The front-end content is fairly simple I could allow what I was currently using. The back-end required more thought as it wasn’t my code and required some compromises, which isn’t ideal. But, anything that makes you think about security and the impact it can have (even if you think your site is insignificant) is a good thing, right?