Wednesday 8 March 2017

Response headers - adding Content-Security-Policy

I recently wrote an update as I continue to work on my response headers, in which I said that I was working on adding content-security-policy, with the help of Scott Helme, who has written a great blog post on this.  He has also created an excellent site called report-uri.io which has a number of tools, including one to help you build your CSP.

As a refresher, this is used to control what access different content on your site has.  For example, you can control what javascript and stylesheets can be included, inline or from different domains, etc.  This can help to limit the attack surface for things like cross-site scripting attacks.

So there are lots of parts, but here's how I went about it...


Default Source (default-src)

This is the default setting, so to be really secure, I went with "none".  This essentially means don't allow any content at all.  It is then overridden for each content type explicitly.

Script Source (script-src)

This is applied to all the javascript files and script tags on the page.  I started with "self", as I wanted everything from my site ("www.rik.onl") to work.  Then I looked through my code and added in the CDN domains that I was using to load the libraries I'm using... "https://code.jquery.com https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com" (space delimited).

Style Source (style-src)

This is applied to all stylesheet files and style tags on the page.  Again, I started with "self", and then needed to add "https://maxcdn.bootstrapcdn.com".

Image Source (image-src)

You guessed it, this is applied to all the images on the page.  This time I needed "self" and also "https://www.gravatar.com".

Font Source (font-src)

I don't load any fonts from my own site here, so I just need to add "https://maxcdn.bootstrapcdn.com".

Connect Source (connect-src)

This is applied to things like AJAX requests, web sockets and event sources.  I don't have any of these currently, so I've left this out, which means it will default to the Default Source, which is "none".  I could also explicitly set this to "none".

Media Source (media-src)

This is applied to audio and video tags.  I don't have any, so I've left this out.

Object Source (object-src)

This is applied to object, applet and embed tags.  I don't have any, so I've left this out.

Child Source (child-src) and Frame Source (frame-src - deprecated)

These are applied to frame and iframe tags.  I don't have any, so I've left these both out.  You should use Child Source instead of Frame Source though, as the later is deprecated.

Worked Source (worker-src)

This is applied to things like service workers, which I don't have, so I've left this out.

Frame Ancesters (frame-ancesters)

This is applied to frame and iframe tags, stating which parents may embed a page.  It replaces the "X-Frame-Options" header, but again, I've left it out.

Form Action (form-action)

This is applied to form tags, stating which location they can post to.  I don't have a form, so I've left it out.  In case you've forgotten, this means it defaults to the "Default Source", which is "none".

Upgrade Insecure Requests (upgrade-insecure-requests) and Block All Mixed Content (block-all-mixed-content)

My site currently runs on HTTP (non-secure), so I've left these out, but I'll definitely be looking to add them in moving forwards.

Reflected Cross-Site Scripting (reflected-xss)

Reflected cross-site scripting is bad!  I've set this to "block".  You can set this to "filter", which means the browser will try to cleanse the script, but I think it's safer to block it completely, if XSS is detected.

Manifest Source (manifest-src)

This is applied to manifest files, so I've set this to "self", as I have a manifest for icons.

Plugin Types (plugin-type)

This tells the browser which plugins they can invoke, such as the Adobe PDF Viewer.  As I don't think my site needs any, I've left this out.

Referrer (referrer)

This directive tells the browser when (and when not) to send the referer [sic] header when fetching content from another domain.  In my last blog post I decided to set the "Referrer-Policy" header to be "no-referrer-when-downgrade", and so I've set this directive to match that.

Report URI (report-uri)

This is where the browser will post violation reports to, so you can keep an eye on what content is breaking.  This could be because you've mis-configured your policy, or it could be because someone is trying to hack your site!  Scott Helme's excellent site report-uri.io will allow you to configure a URI which you can set here.


So now it's ready for testing!  

To test, instead of setting "Content-Security-Policy", set "Content-Security-Policy-Report-Only".  This means that the browser will report all of the violations, but will continue to load the content anyway, which is perfect until you're sure it's right.  

This is what I came up with...

default-src 'none'; script-src 'self' https://code.jquery.com https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com; style-src 'self' https://maxcdn.bootstrapcdn.com; img-src 'self' https://www.gravatar.com; font-src https://maxcdn.bootstrapcdn.com; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; manifest-src 'self'; referrer no-referrer-when-downgrade; report-uri https://rik.report-uri.io/r/default/csp/reportOnly;

I then reloaded my site, checked the console, and saw a number of violations!

This is because I'd forgotten a couple of included scripts that are loaded by Google Analytics.  In fact, they also use an inline script tag, but I really don't want to add "unsafe-inline" to the Script Source, otherwise all inline scripts could be run.  

Luckily you can fix inline script and style tags that you want to allow by calculating a SHA-256 hash of the contents and including this in the Script Source.  And Scott's got a hash generator tool as well, so that's easy.

Having fixed these problems, and reloading my site with no violations reported, I'm now ready to start enforcing.  This means that I need to set the "Content-Security-Policy" header, and if you're using report-uri.io then you need to update your Report URI directive as well.

Note that if you want to support IE11, you also need to set "X-Content-Security-Policy" to the same value.  It's not supported in older versions of IE at all.

Now that I've added these extra headers, you can check out my live report.  Last I checked, I got an A+ 😃

Saturday 4 March 2017

Response headers - an update

I previously wrote about what response headers I was sending back from my website - now I have an update.

Part of the problem was that extra headers were being sent, which I didn't particularly want to be sent.  So I've been working on getting rid of them.

X-Hostname

I believe this is added by my web host, but I managed to remove it by modifying my .htaccess file with the following...

  Header unset X-Hostname

X-Powered-By

This is added by PHP, but it was easily removed by modifying my php.ini file with the following...

  expose_php = Off

Server

I could not change this, unfortunately, due to the fact that I'm currently using shared hosting, and therefore don't have access.  But for others, whilst it can't be removed, it can be changed to minimise it's output, by adding the apache directives...

  ServerTokens ProductOnly
  ServerSignature Off

So now I've tidied that up a bit, I wanted to look at what else I should be adding.  I found an excellent site for this by Scott Helme called securityheaders.io.  You simply scan your site, and follow the advice it gives you.  

It warned me about the "Server" header, but I've already worked out I'm going to have to live with that.  Other headers it suggested that I add included...

Referrer-Policy

This is used to define what referrer information gets sent when someone clicks on a link on your site that goes to another site, or even a page within your own site.  Scott Helme has written a great blog post on this, in which he recommends going with "no-referrer-when-downgrade", which sounds good enough for me.  My site is currently shipped over HTTP, but when I move it to HTTPS (yes, this is the plan!) then it will ensure referrer information isn't passed on to HTTP sites.

Content-Security-Policy

This is used to control what access different content on your site has.  For example, you can control what javascript and stylesheets can be included, inline or from different domains, etc.  Again, Scott Helme has written another great blog post on this.  He has also created an excellent site called report-uri.io which has a number of tools, including one to help you build your CSP.  This is a bit more involved though, so I think I'll cover this in a separate post.