Introduction

The Content Security Policy (CSP) is a security mechanism web applications can use to reduce the risk of attacks based on XSS, code injection or clickjacking. Using different directives it is possible to lock down web applications by implementing a whitelist of trusted sources from which web resources like JavaScript may be loaded. Currently the CSP version 2 is supported by Firefox, Google Chrome, and Opera, whereas other browsers provide limited support or no support at all (Internet Explorer)[4].

The CSP has two modes of operation [7]: enforcing and report-only. The first one can be used to block and report attacks whereas the second one is used only to report abuses to a specific reporting server. In this blog post, we will focus only on the enforcing mode.

The policy, in order to work, has to be included in each HTTP response as a header (“Content-Security-Policy:”). The browser will then parse the CSP and check if every object loaded in the page adheres to the given policy. To specify these rules, the CSP provides different directives [5]:

  • script-src: defines valid sources of JavaScript
  • object-src: defines valid sources of plugins, like <objects>
  • img-src: defines valid sources of images
  • style-src: defines valid source of stylesheets
  • report-uri: the browser will POST a report to this URI in case of policy violation

Each of these directives must have a value assigned, which is usually a list of websites allowed to load resources from. The default behavior of directives if omitted, is to allow everything (“*”) without restrictions [9]. A basic example of a valid CSP is shown below:

Content-Security-Policy: default-src 'self'; script-src compass-security.com

The directive “default-src” is set to ‘self’, which means same origin. All resources without a directive set are allowed to be loaded only from the same origin, in this case “blog.compass-security.com”. Setting the “default-src” directive can be a good start to deploy your CSP as it provides a basic level of protection. “script-src” is used to allow all JavaScripts to be loaded from the domain “compass-security.com”, via HTTP (https:// should be explicitly specified) without allowing subdomains. These could be specified directly (e.g. sub.compass-security.com) or using the “*” wildcard (*.compass-security.com)

Misconfigurations and Bypasses

Even though it is possible to have a good level of control over the policy, errors in the definition of directives may lead to unexpected consequences. Misconfiguration or ambiguities can render the policy less efficient or easy to bypass. In addition, the functionality of the application could also be broken. The following example illustrates what can happen if “default-src” is omitted:

Content-Security-Policy: script-src compass-security.com

Now, all the scripts with source “compass-security.com” are allowed. But what about the other objects like stylesheets or flash applets? The policy above can be bypassed for example using this payload, which triggers an alert box using a Flash object[7]:

">'><object type="application/x-shockwave-flash" 
data='https://ajax.googleapis.com/ajax/libs/yui/2.8.0r4/build/charts/
assets/charts.swf?allowedDomain=\"})))}catch(e{alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>

One other common mistake is the inclusion of the dangerous “unsafe-inline” or “unsafe-eval” directives. These allow the execution of potentially malicious JavaScript directly via “<script>” tags or eval():

Content-Security-Policy: default-src 'self'; script-src compass-security.com 'unsafe-inline';

This policy defines the default source as “self” and allows the execution of script from “compass-security.com” but, at the same time, it allows the execution of inline scripts. This means that the policy can be bypassed with the following payload [7]:

">'><script>alert(1337)</script>

The browser will then parse the JavaScript and execute the injected malicious content.

Besides these trivial misconfigurations shown above, there are some other tricks used to bypass CSP that are less common and known. These make use, for example, of JSONP (JSON with padding) or open redirects. Let’s take a look at JSONP bypasses.

If the CSP defines a whitelisted JSONP endpoint, it is possible to take advantage of the callback parameter to bypass the CSP. Assuming that the policy is defined as follows:

Content-Security-Policy: script-src 'self' https://compass-security.com;

The domain compass-security.com hosts a JSONP endpoint, which can be called with the following URL:

https://compass-security.com/jsonp?callback={functionName}

Now, what happens if the {functionName} parameter contains a valid JavaScript code which could be potentially executed? The following payload represents a valid bypass [7]:

">'><script src="https://compass-security.com/jsonp?callback=alert(1);u">

The JSONP endpoint will then parse the callback parameter, generating the following response:

Alert(1); u({……})

The JavaScript before the semicolon, alert(1), will be executed by the client when processing the response received.

URLs with open redirects could also pose problems if whitelisted in the CSP. Imagine if the policy is set to be very restrictive, allowing only one specific file and domain in its “script-src” directive:

Content-Security-Policy: default-src: 'self'; script-src https://compass-security.com/myfile.js https://redirect.compass-security.com

At first sight, this policy seems to be very restrictive: only the myfile.js can be loaded along with all the scripts originating from “redirect.compass-security.com” which is a site we trust. However, redirect.compass-security.com performs open redirects through a parameter in the URL. This could be a possible option to bypass the policy [7]:

">'><script src="https://redirect.compass-security.com/redirect?url=https%3A//evilwebsite.com/jsonp%2Fcallback%3Dalert">

Why is it possible to bypass the CSP using this payload? The CSP does not check the landing page after a redirect occurs and, as the source of the script tag “https://redirect.compass-security.com” is whitelisted, no policy violation will be triggered.

These are only a small subset of possible CSP bypasses. If you are interested, many of them can be found at [6] or [7].

The “nonce” directive

Besides the whitelist mechanism using URLs, in the CSP2 there are other techniques that can be used to block code injection attacks. One of these is represented for example by “nonces”.

Nonces are randomly generated numbers that should be defined in the CSP and included only inside <script> or <style> tags to identify resources and provide a mapping between the policy and the client’s browser. An attacker injecting a payload containing a script tag has no knowledge of the nonce previously exchanged between the client and the server, resulting in the CSP detecting this and throwing a policy violation. A possible configuration of a CSP with nonces could be:

Content-Security-Policy: script-src 'nonce-eED8tYJI79FHlBgg12'

The value of the nonce (which should be random, unpredictable, generated with every response, and at least 128 bits long [10]) is “eED8tYJI79FHlBgg12”.

This value should be then passed to each script tag included in our application’s pages:

<script src="http://source/script.js" nonce="eED8tYJI79FHlBgg12">

The browser will then parse the CSP, check if the scripts included have a matching value and block those that do not include any valid nonce. This technique works great against stored XSS, as the attacker cannot include valid nonces at injection time. Another advantage is that there is no need to maintain whitelists of allowed URLs, as the nonce acts as an access token for the <script> tag and not necessarily for the source of the script. It is also possible to use hashes in order to identify the content of each <script> element inside the page, more information about this feature can be found at [8].

Conclusion

We have seen that the CSP is a very useful tool web developers can use to have better control on the loaded resources. The different directives provide flexibility to allow or deny potentially dangerous web resources inside web pages. However, it is also easy to make errors if too many URLs are whitelisted (e.g. hidden JSONP endpoints). Here at Compass we encourage the use of the CSP as an additional barrier against web threats. Nonetheless, I would like to stress that the first protection against code injection should always be provided by a solid input/output validation, which can help also against other common attacks like SQL injections.

If you would like to get more information about how web applications should be protected, or you want to deepen your web security knowledge we provide different trainings:

We are also offering trainings in other areas of IT Security. You can check the different topics here:

Sources & References

  1. https://www.owasp.org/index.php/Content_Security_Policy
  2. https://www.w3.org/TR/CSP2/#intro
  3. https://w3c.github.io/webappsec-csp/#match-element-to-source-list
  4. http://caniuse.com/#search=Content%20Security%20Policy%20Level%202
  5. http://content-security-policy.com/
  6. https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it’s-CSP!%22.
  7. http://conference.hitb.org/hitbsecconf2016ams/materials/D1T2%20-%20Michele%20Spagnuolo%20and%20Lukas%20Weichselbaum%20-%20CSP%20Oddities.pdf
  8. https://blog.mozilla.org/security/2014/10/04/csp-for-the-web-we-have/
  9. http://www.html5rocks.com/en/tutorials/security/content-security-policy/
  10. https://www.w3.org/TR/CSP/#source_list