01/06/2014

Second Line of Defense in Web Applications Part 3 Content Security Policy

If correctly implemented Content Security Policy (CSP) might very well cause the death of  99% of all XSS vulnerabilities and exploits. Unfortunately correctly implemented in the sense of CSP means that there are a lot of restrictions on the way web applications are built.
But what is this CSP? As the name states it is a policy that specifies where content may come from. The policy is written by the web applications developers and is sent to the browser via the HTTP header: “X-Content-Security-Policy” (or with the “X-” prefix omitted) The browser then enforces the policy.

script-src self 'google.com';
font-src self 'fonts.googleapis.com';
img-src *;
default-src self;
style-src self unsafe-inline;

This example policy allows that JavaScript may come from the own domain, which is represented by the self keyword, and google.com. Fonts may come from the own domain and fonts.googleapis.com. Images can be included from anywhere on the web. “default-src” is a catch all for all non-specified elements. CSS stylesheets may come from the own domain and “unsafe-inline”. But what is the “unsafe-inline” origin?
This shows the feature of CSP that will prevent most XSS attacks. With CSP enabled inline JavaScript, the eval() function and inline CSS are forbidden. This means that every piece of JavaScript or CSS must be in a separate file. We are talking about externalized scripts and styles.

Let’s look at an example how web applications might look today. Let’s say we have an HTML file called “voodoo.html” which contains some JavaScript code to do something:

<!-- ... -->
<script>
function performVoodoo() { alert('voodoo'); }
</script>
<a href="#" onClick="performVoodoo();">Click Me!</a>
<!-- ... -->

Now this piece of JavaScript code will trigger a policy violation. So the code must be moved to a separate file. Our “voodoo.html” would then look like this with the JavaScript code moved to “voodoo.js”

<head>
<!-- ... -->
<script src="voodoo.js"></script>
</head><body>
<a href="#" id="voodoo">Click Me!</a>
<!-- ... -->

“voodoo.js” could look like this:

function performVoodoo() { alert('voodoo'); }

document.addEventListener('DOMContentLoaded', function () {
document.getElementById('voodoo')
.addEventListener('click', performVoodoo);
});

As you can see externalizing scripts takes some work and many existing web applications might be hard to secure with CSP against XSS. When building new web applications, scripts and styles should be externalized from the beginning. This does not only result in the possibility to use CSP but also cleaner code, with markup, stylesheets and code cleanly separated.
For legacy applications we can still allow inline scripts and stylesheets using the “unsafe-inline” directive of CSP. This can still prevent exploitation of XSS vulnerabilities, since often XSS payloads are restricted in their size. Therefore attacker rely on including remote scripts, which CSP can still prevent.

CSP also supports reporting policy violations back to the web application and a report-only mode, which can be used during CSP deployment. Content Security Policy is currently supported by Chrome 21+, Firefox 4+ and IE 10+.

While correct CSP usage can prevent exploitation of almost all XSS vulnerabilities, this must still be considered only the second line of defense because of two reasons.

  1. Browser support. Some minor mobile browser might not implement CSP and therefore still be vulnerable.
  2. There are attacks that do not even use JavaScript. The most obvious one is site defacement. It has also been demonstrated that there are attacks that do not even involve JavaScript. *

You can find more information here, here and here.