Frontend security with CSP

Krzysztof Szromek CEO

Most of the time we’re thinking about web security in terms of backend development, leaving the frontend with HTTPS and nothing more. Having a secured channel is a must have these days, but it shouldn’t be the only thing that we think off when it comes to securing our application on the users’ end.

Every security solution is like a slice of cheese- it may have some holes, leaving our application at risk. This is why we need to stack many layers till we don’t see any holes left.
With that in mind we need to consider HTTPS being only first layer of our security stack. I’d like to explain a little bit more about second most important (in my opinion) layer which is Content Security Policy.

What is CSP?

Content Security Policy is an HTTP response header that reduces the risk of XSS attack by whitelisting sources of images, scripts, styles and other resources. It is supported by top browsers, excluding IE (although there’s Edge support since build 10240+).

Browser support for CSP 1.0 http://caniuse.com/#search=content%20security%20policy

Currently there are two versions of CSP available, where version 1.0 has a better support coverage, but version 2.0 adds a number of new directives and capabilities thus should be considered as more robust solution.

CSP Examples

When you want to allow resource loading only from the same origin this is how CSP header looks like:

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

If you only want to restrict specific kind of resources for example scripts, you can do following:

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

Most of pages are using Google Analytics and Google Ajax CDN, this is all you need to enable those scripts:

Content-Security-Policy: script-src 'self' www.google-analytics.com 
ajax.googleapis.com;

You can see a list of all possible attributes here: https://content-security-policy.com/

How to start

By enabling a Content-Security-Policy header in an existing application you’ll disable loading of all non-listed sources potentially breaking the page for a user. I recommend to start with Content-Security-Policy-Report-Only.

Content-Security-Policy-Report-Only: script-src 'self' 
www.google-analytics.com ajax.googleapis.com; 
report-uri /my-post-webhook.php

It works the same way as Content-Security-Policy, but instead of blocking the resource it throws an error in form of a JSON. You can handle it by yourself as they will be send via POST to a given URL, or use a service that will handle it for you (e.g. https://report-uri.io/).

You can record those errors and refine your policy, to the point where all needed sources are whitelisted and you don’t get any errors. It’s worth noting that Content-Security-Policy-Report-Only and Content-Security-Policy can coexists, so you can use one to block resources, and the other one to develop more strict policy versions for better security.

Content-Security-Policy: script-src script-src 'self' 
www.google-analytics.com ajax.googleapis.com; 
report-uri /my-post-webhook.php;
Content-Security-Policy-Report-Only: script-src 'self; 
report-uri /my-post-webhook.php

Server setup

Apache

Add the following to your httpd.conf in your VirtualHost or in an .htaccess file:

Header set Content-Security-Policy "default-src 'self';"

Nginx

In your server {} block add:

add_header Content-Security-Policy "default-src 'self';";

Further reading

https://content-security-policy.com/