Written by Giles Bennett
It used to be that hacks, and attempted hacks, on e-commerce sites were quite unsophisticated. Use brute force to hack an admin account with an insecure password, pop a bit of code in the footer of the site to scrape any requests for URLs that included the word 'checkout' to a publicly accessible file for later collection - about two years ago we came across a store where this had happened, with the file at 1GB and counting - decrypting just 1MB of it found two complete sets of names, addresses and card numbers.
Nowadays, though, things are getting more sophisticated - a recent hack we saw used the inclusion of an external JS file, loaded over https://, from a 'respectable' sounding domain like 'jscdn.com' (it wasn't that, but something similar) to post card data to a remote URL.
As the hackers get more sophisticated, so do store owners and their hosts. We now require that our clients implement a Content Security Policy, and put one in place for every site that we host - so here's a quick run down of the why and how of CSPs.
In short, a Content Security Policy is a header added to the response from a web server with a list - that list shows what sources should be trusted for the various different types of resources which go into making up a web page. If a page says to load a resource of a type which is not permitted by the Content Security Policy, the browser knows to ignore it. So in the example above, then, given that 'jscdn.com' wouldn't have been in the permitted list of sites from which JS resources could have been loaded, the script would have been automatically blocked - problem solved.
A CSP can have various directives, one for each of the main types of resource - there are about fifteen of these, covering scripts, fonts, form actions, frame sources, images, media (video and audio), objects (Flash and similar plugins), styles, and more. By default, they are wide open - so if you don't specify a font-src section, then the page can load fonts from any location. To prevent that, the fallback is the default-src directive, which states valid sources for any *-src directives. So, for example, on our site our default-src is https://hummingbirduk.com - as a result, if we didn't specify a script-src (although in practice we do) then only scripts from https://hummingbirduk.com would be allowed.
Each directive, therefore, specifies the permissible sources for its type of resource. Most commonly this will be a URL, but can also be 'self', which matches the page origin (but not any subdomains), 'unsafe-inline' (for inline JS and CSS) and 'unsafe-eval' for scripts that convert text to JS like the eval function. It's worth mentioning that CSP considers inline JS to be inherently harmful because it can be generated as a result of a cross-site scripting attack, leaving the browser with no way to determine if the script is from a legitimate source or not. The safest option is to therefore disallow it, and to ensure that any JS currently being loaded inline is moved to separate script files (which is best practice anyway) and loaded from those instead.
One problem can be that chasing down all the sources can be a bit like playing Whack-A-Mole, particularly when you're including tools to post to social media. Allowing a script from facebook.com, for example, may result in it calling a script from facebook.net, which in turn tries to load an image from cdn.facebook.com, which then tries to load an image from cdn.facebook.net...and so on. For domains which you are prepared to trust, then you can use a wildcard (https://*.google.com) to allow any scripts from the facebook.com domain, but naturally this does result in a degree of dilution of the security. If a hacker gets their hands on a Google sub-domain, though, then we probably have bigger things to worry about.
A CSP can be implemented via a meta-tag - although that doesn't allow one to declare a policy for the frame-ancestors, report-uri or sandbox directives - but is more commonly implemented by setting the appropriate HTTP header.
Once implemented, if a resource is blocked by the browser, a console note to that effect will be shown, specifying the source from which the resource was to have been loaded, and directive its loading would have been in contravention of.
This is the best way of seeing if anything's being blocked that shouldn't be - thus resulting in tinkering with the CSP until it's all good.
For a relatively small amount of effort, CSP implements a great level of security onto a site. Whilst allowing inline JS undoes a little of that benefit, the effort to move all inline JS to external styles may well be disproportionately expensive, but given the rise of hacks featuring inclusion of malicious scripts from external sources, this is a quick and easy way to protect against such incursions.