Area41 2024 - A Recap
Michael Schneider
The Content Security Policy (CSP) has been a separate checkpoint for our Web Application Penetration Tests since September 2015. One of the first projects so tested is emblematic of the acceptance and implementation of CSP in general. In that project, multiple cross-site scripting (XSS) vulnerabilities were found. Along with strict input validation, we also recommended introduction of a CSP header as an additional measure. The developers implemented this and defined a policy. But the script-src
directive continued to permit execution of inline JavaScript. This effectively meant installation of a policy that offered no real protection against XSS attacks. In the end, the CSP header was taken out again. No additional resources were invested in a stricter policy definition or an amendment to the web application.
Introduction of an effective Content Security Policy is a demanding task, one that should be carried out in accordance with web development. This article describes how CSP came about and how it is used in practice.
The first draft of the Content Security Policy Level 1 was published by the W3C Consortium on 15 November 2012. Browser vendors initially implemented it as an experimental function with the header X-Content-Security-Policy
or X-WebKit-CSP
.
The goal of CSP is to provide both web developers and web server administrators with a tool for mitigation of injection vulnerabilities. When this kind of policy is defined, the web browser is informed which web application resources will be loaded and processed, such as images, style sheets (CSS) or scripts. Here, CSP should be considered a component of a defense-in-depth strategy rather than a replacement for input validation or coding of output.
The X-Content-Security-Policy
header is supported by Mozilla Firefox (since Version 4) and Microsoft Internet Explorer 10, but is already considered obsolete and should no longer be used. The Content-Security-Policy
header stands for CSP Level 1 and all further levels. It has been supported since browser versions Google Chrome 25, Mozilla Firefox 23, Safari 7 and Internet Explorer Edge.
Through directives, the policy can be tailored to the intended use of the web application. A directive is an instruction to a web browser how to handle several resource types. The default-src
directive is considered the standard for all other directives where they are not specified. Directives exist for management of JavaScript, images, objects and style sheets (CSS). Each directive is defined by a source expression. Valid values include none
, self
, data:
and one or more hosts/domains. The Content Security Policy Reference offers a good overview.
In the case of the directive for JavaScript named script-src
, it became apparent that the existing source expressions were insufficient for real-life scenarios and thus inhibited implementation of CSP. With Level 2, published on 21 July 2015, the attribute nonce
was introduced to ensure additional flexibility. The following section discusses its use – and shortcomings.
The frame-ancestors
directive was also introduced with the aim of replacing the HTTP header X-Frame-Options. Here, the expression none equates to the value DENY
in the HTTP header. Veit Hailperin already explained this header in his article Inglorious Headers. For now we recommend a dual use strategy, set the policy and the header for it self because not all browsers support this CSP level.
The nonce
attribute has not caught on in practice. It was the inclusion of JavaScript libraries from third-party sites that proved particularly problematic. The introduction of the source expression strict-dynamic
in the Working Draft for the CSP Level 3 dated 21 June 2016 attempts to solve this. As a further change, the directive report-uri
was renamed report-to
.
Where CSP has not previously been used, we recommend starting with the following directive:
default-src “none”; script-src “self”; connect-src “self”; img-src “self”; style-src “self”;
This will allow the use of images, styles (CSS) and JavaScript from your own domain. When using JavaScript, however, this also means that only integrated script files are executed. Any in-line instructions in script tags are not permitted. For web applications developed in this way, this leads to the problem that the script element is processed directly in the HTML code.
To avoid recoding the entire website, the directive is usually expanded to include the expression unsafe-inline
. This means that the web application continues to function as usual, but is once again vulnerable to reflected or stored XSS attacks. This removes the benefit, or protective effect, of the policy.
In many web applications, the use of JavaScript is not restricted to the owner“s domain. External libraries are also integrated into the context of the owner“s page. This means that a whitelist of such domains has to be maintained in the script-src
directive. Maintenance is no easy matter and in a worst-case scenario can even lead to a CSP bypass. This is vividly illustrated in solutions for the mini-challenge by Cure53 entitled “H5SC Minichallenge 3: Sh*t, its CSP!.
With the introduction of the attribute nonce
in CSP Level 2, there is now the option of use of embedded script elements. The principle behind nonce
is that a random nonce value is recorded in the script-src
directive. Ideally, this occurs through the web application itself. Every script element that sets this value in the nonce
attribute is then authorized. This means that legitimate script elements are executed, but XSS attacks are stopped.
The use of libraries, including JavaScript CDNs like jQuery, React.js and AngularJS, in conjunction with nonce
leads to a new problem as described below. The nonce
attribute is defined as:
Content-Security-Policy: script-src “nonce-i7bGtfs”
A library is then integrated into the website and correctly provided with the matching value in the nonce
attribute:
<script src=“https://cdn.example.com/script.js” nonce=“i7bGtfs”></script>
Because the correct value for nonce
is set, the integration of the library is permitted. But if further libraries are reloaded as dependencies in the library itself or a script element is used, this leads to an error since the value for nonce is not set there. The second case relates to parser-inserted script elements. A simple example of a parser-inserted element looks like this:
var scriptPath = “https://othercdn.not-example.net/dependency.js” document.write(“<script src=” + scriptPath + “></script>”);
With the expression strict-dynamic
, CSP Level 3 offers a solution for this problem and simplifies the use of external libraries. Using strict-dynamic
in conjunction with nonce
results in two changes, or effects:
default-src
or script-src
, as well as the use of unsafe-inline
, are rejected.For practical purposes, this offers two benefits. The first effect permits a backwards-compatible rollout of strict-dynamic
. The policy
Content-Security-Policy: “unsafe-inline” https: “nonce-abcdefg” “strict-dynamic”
becomes "unsafe-inline" https:
in browsers that support CSP Level 1. The https: "nonce-abcdefg"
part applies in the case of Level 2 support and "nonce-abcdefg" "strict-dynamic"
applies in browsers that have implemented CSP Level 3. The second effect entrusts the integrated script with the integration of its own dependencies without the need to list them specifically in the whitelist.
One worthwhile presentation on CSP bypasses and the introduction of strict-dynamic
is the talk by Lukas Weichselbaum and Michele Spagnuolo, both information security engineers at Google, entitled Breaking Bad CSP! at this year“s Area41 2016. The slides from the talk are also available.
The Content-Security-Policy
header instructs the web browser to enforce the defined directives. This can, and experience shows that it does, lead to problems with the introduction of CSP or in the development phase of web applications. Therefore, a second CSP header called Content-Security-Policy-Report-Only
reports infringements of the directive without blocking them. The web browser sends a report to the URL defined in the directive report-uri
or, in future, report-to
.
The report contains the following elements:
document-uri
– the page where the infringement occurredreferrer
– the referrer of the pageblocked-uri
– the base address of the blocked URIviolated_directive
– the specific directive that was infringedoriginal-policy
– the complete CSPThese reports can be evaluated in respect to overly strict directives, infringements of the directive caused by programming errors or flaws in the web application, as well as potential XSS attacks. The IT security researcher Scott Helme offers a free service for collating and evaluating CSP reports at the website report-uri.io. This website is suitable for a first attempt with CSP without the need to build a reporting infrastructure, or with publicly accessible websites that do not contain sensitive data. For sensitive websites, the report service should be operated by a system under your own control.
With strict-dynamic
, Content Security Policy Level 3 provides a function that offers sufficient flexibility for productive use. The reporting function also offers a reasonable estimation of the consequences of implementation of CSP. This function means that you can test, step by step, how individual directives are configured, so that they offer the greatest level of restriction without hindering the functionality of the website. Web development itself ideally should conform to a policy and essentially refrain from use of inline functions for CSS or JavaScript. Since 2012, continuous work has been carried out on CSP to improve its functionality and simplify its implementation. CSP should no longer be seen as a bogeyman that endangers website operations, but rather as another layer in a secure web application. We would certainly prefer to be able to analyze more CSP headers in the future, instead of simply entering the CSP header is not set in the checklist.
Our experts will get in contact with you!
Michael Schneider
Michael Schneider
Michael Schneider
Michael Schneider
Our experts will get in contact with you!