Security is Layers

One of the things you lean when working with computer security is that lots of layers is a good approach to making a site secure. You can make some quick wins or reduce the chance of an attack by maybe 90% but to get that warm feeling of security, you need to pile on the layers.

Content-Security-Policy

One of these layers is called Content Security Policy and is an HTTP trick to help avoid cross-site-scripting and similar injection-based attacks. For example, if someone finds how to add a script to a page on your web site, this script could pretty much capture anything the user is doing (including typing login credentials) and send it to another site, without the user even knowing. Since the web is designed to work cross-domain, this will work and no-one will know.

Content Security Policy is an easy enough concept to understand. It does several things but the largest of these is that it tells the browser what domains it is allowed to load external files from. These include common links such as images and scripts but also allow you to specify the policy for fonts, objects, ajax connects, media, style sheets and frame sources. These can either be specified globally in a simple statement like Content-Security-Policy: 'self' or a much more complex policy such as Content-Security-Policy: 'none'; script-src: 'self'; font-src: http://fontsource.net http://fontawesome.net; media-src: https://mymediasource.com

The theory is pretty straight-forward. Anything not specified inherits the default value (none is a useful default) and you can either specify 'none', 'self' and/or URLs to restrict the origin of external files (you are allowed to combine self and URL(s))

Restricting Javascript and CSS

Another feature of CSP is to lock-down inline script and css. Preventing scripts from other domains will not help if someone is able to inject a script directly into your page, rather than just a link to a script, so CSP allows you to set a special flag against script-src and style-src of 'unsafe-inline', which tells the browser to allow inline script and styles. Where possible, you should not allow inline scripts/styles although apart from the work of moving any existing code out of the page, you might well have existing libraries that use inline scripts or styles and which you don't have direct control over. For this reason, you can and should use the report-only option when creating your policy which will tell the browser to report errors but not to restrict the content. This way you can see any problems before you start locking your system down.

A second part, which applies to Javascript, is a very large security hole, also known as the eval() function which allows you to execute the text passed to the function as if it was code. Naturally, this allows all manner of exploits depending on how the user can get the code/text into the page and, again, is disallowed by default when CSP is enabled. You can allow its use by specifying 'unsafe-eval' against the script-src section. Note that in .Net, the validators use eval(), which is annoying and means this measure cannot be used currently (although there is a chance I will rewrite my validators to do something different).

Stitching it Together

Basically, to code this, you need a basic string machine which you set various properties on and which ultimately outputs a single string which needs to be attached as a header to the HTTP response for your site pages. It could be set differently for different pages if required. I have created a .Net helper class to do this, which is available for free on github.

Weaknesses

There are two weaknesses to this system (although these weaknesses are still stronger than doing nothing). The first, already mentioned, is that you sometimes have to make the policy less restrictive to make up for the fact that libraries outside of your control might use unsafe methods.

The second is that if you are using a popular content delivery network (CDN), then it would perhaps be trivial for an attacker to put their evil script on the same CDN and it be allowed by your policy. For this reason, you cannot use CSP as a control by itself, it needs to be part of a layered approach to security. You can also be specific in the path of your URL, for instance, you could use http://maxcdn.com/libs/jquery/ instead of http://maxcdn but you need to include a trailing slash if it is part of the path to the real file (rather than a full path) otherwise it won't work.