Content Security Policy (usually abbreviated as CSP) is a way for web pages to restrict the sites allowed to include content within the page. It also can restrict whether inline scripts are allowed to run and inline styles/CSS are allowed to be applied to the page. In general, CSP allows web developers greater control over their content, helping mitigate several security problems. One major benefit of CSP is that, by default, it prevents inline scripts from executing. This greatly helps mitigate the threat of XSS (Cross Site Scripting) or other forms of script injection. For a great introduction to CSP, see Mike West’s post “An Introduction to Content Security Policy”.
The idea of a document being able to specify content restrictions dates back to at least 2007, when it was discussed by both Gervase Markham of the Mozilla Project, and Robert ‘rsnake’ Hansen, a security researcher. Brandon Sterne and Sid Stamm worked on an initial prototype implementation of CSP for Firefox long before an official specification existed. This ‘pre-spec’ implementation of CSP landed in Firefox 4.0 in March 2011, and used the X-Content-Security-Policy header. The concept of CSP gained traction fairly rapidly, with Chrome shipping their first implementation, using the X-Webkit-CSP header, in August 2011. After much discussion among security and web experts, in November 2011 a working draft of a W3C specification for Content Security Policy 1.0 was published. The syntax specified by the working draft was quite different from the syntax used by the initial Firefox implementation, as concepts had over time evolved and been refined. A year later, the CSP 1.0 spec reached the Candidate Recommendation stage, where it was ready to be implemented. Chrome shipped support for the CSP 1.0 spec using the unprefixed header in Chrome 25 last February. Internet Explorer 10 added support for CSP’s ‘sandbox’ directive in Internet Explorer 10, but it does not support the rest of the CSP directives currently.
What changed between the original Firefox CSP implementation and the CSP 1.0 spec ?
- The Header has Been Unprefixed
- Changes to the Available Directives
- Changes to Default Behavior
- Changes to Allowing Inline Script and the Use of eval()
- Blocking Inline Styles
Instead of X-Content-Security-Policy, the spec defines the Content-Security-Policy header. This is great, because we no longer have the situation where a site has to send multiple CSP headers (with different syntax !) to have its policy enforced in CSP-supporting browsers. The same Content-Security-Policy header will work for Firefox, Chrome, IE 10 (sandbox only) and any other browsers that implement the spec. If for some reason a site sends both the X-Content-Security-Policy header and the Content-Security-Policy header, the prefixed header will be ignored and only the policy from the unprefixed header will be applied.
The directives available within a policy changed somewhat. The original Firefox CSP implementation used the ‘allow’ directive to specify the default policy that will be used for unspecified directives. This has been replaced by the ‘default-src’ directive in CSP 1.0. Additionally, Firefox’s original implementation used the ‘xhr-src’ directive to restrict the origins to which an XMLHttpRequest object can connect. In the 1.0 spec, ‘xhr-src’ was replaced by ‘connect-src’ – which, in addition to XHR, also restricts where EventSource and WebSocket objects can connect.
The initial Firefox implementation of Content Security Policy failed closed, meaning that future syntax wasn’t backwards compatible. In CSP 1.0, a missing default-src directive falls back to allowing all sources.
The method for opting into allowing inline script and the use of eval() changed. In the original Firefox CSP implementation, the ‘options’ directive was used with values inline-script and eval-script to do this. For example, an original CSP policy of “allow ‘self’ ; options inline-script eval-script” would allow content to be loaded from the same origin as the CSP-protected document and also allows inline scripts to execute and eval() to be used.
In CSP 1.0, additional keywords have been added to the ‘script-src’ directive to handle this situation. ‘script-src: unsafe-inline’ opts into allowing inline script and ‘unsafe-eval’ opts into allowing the use of eval(). Both keywords can be specified to opt into doing both, although this decreases the value of using CSP quite a bit ! For example, a CSP 1.0 policy of ‘default-src ‘self’ ; script-src ‘unsafe-inline’ ‘unsafe-eval’ allows content to be loaded from the same origin as the CSP-protected document and also allows inline scripts to execute and eval() to be used.
Firefox’s original CSP implementation did not block inline styles at all. This was a later addition to the CSP spec. It aims to prevent attacks via injecting <style>
elements or another HTML element with a style attribute. These attacks can be carried out even when executing script is not allowed. Some potential attacks include using CSS selectors to exfiltrate data from the page and using attributes to overlay one element on top of another, leading to a possible phishing attack.
Are there still some differences between the Firefox CSP 1.0 implementation and the spec ?
Yes, some fairly minor ones.
- The frame-ancestors directive is still supported. This directive is similar to the X-Frame-Options header, restricting which sites are allowed to frame the webpage. The X-Frame-Options header has been deprecated and also had some issues as originally specified. It’s been proposed that this functionality be rolled into CSP, via the frame-options directive. frame-options is a new CSP directive proposed as part of the “User Interface Security Directives for Content Security Policy” spec under development. At some point, Firefox’s frame-ancestors directive will likely be deprecated in favor of frame-options.
- The report-uri directive allows a policy to specify where CSP violation reports are sent. In Firefox, this is limited to sending reports to the origin of the document which specified the CSP. There’s ongoing discussion on the correct restrictions and concerns around reports, both within the W3C WebAppSec working group and Mozilla, please see Bug 843311
- The SMIL animation elements
and are blocked when inline styles are blocked. The biggest driver for this is Bug 704482 – a very clever attack from Mario Heiderich which allows reading key strokes even when script is not allowed to execute. We are taking the cautious approach here and plan to bring this up within the W3C WebAppSec working group.
- Firefox does not support the ‘sandbox’ directive. This directive is optional in the CSP 1.0 spec, but is planned to be part of CSP 1.1.
What does the future hold for CSP in Firefox ?
We plan to deprecate the X-Content-Security-Policy header at some point. Part of the motivation for this post is to let people know it’s time to transition their sites to using the unprefixed Content-Security-Policy header. Firefox displays a message in the web console informing web developers the prefixed header will be deprecated in the future.
Additionally, we’re participating in the development of the CSP 1.1 spec via the W3C WebAppSec working group and Mozilla’s Dan Veditz is one of the editors of this spec. We’re especially excited about the new nonce-source source for the script-src and style-src directives. This source allows the whitelisting of specific inline scripts and styles if they provide the same valid nonce specified in the policy. nonce-source was recently implemented in Blink and is under development in Firefox. See section 4.10.1 “Usage” in the CSP 1.1 spec for details and please note that this spec is still rapidly evolving !
Within Mozilla we also have discussed taking the inline style blocking of CSP further. In particular, there’s a desire to add similar functionality to blocking eval() – the rationale is that constructing styles from strings is also inherently dangerous. Bug 873302 covers this and some of the discussion around this is contained within the original ‘block inline styles’ bug . We plan to bring this up within the W3C WebAppSec working group in the very near future to collect more feedback on this idea. It’s also been proposed within Mozilla (and discussed somewhat within the working group) to create a CSP directive that would block the usage of .innerHTML. While injecting script elements via innerHTML would be blocked by a CSP that blocks inline scripts, there are many other problems that can result from using untrusted input in .innerHTML.
That was too long, just tell me where can I use the Content-Security-Policy header now ?
- Firefox : now in desktop Firefox 23 (Aurora) and later. Firefox for Android and Firefox OS soon to follow.
- Chrome : 25 and later
- Internet Explorer : 10 and later (sandbox directive only)
- The original lead for developing CSP at Mozilla: Brandon Sterne
- Mozilla Security Engineering & Security Assurance, especially Sid Stamm, Brian Smith, Daniel Veditz, Garrett Robinson, Mark Goodwin, Frederik Braun, and Tanvi Vyas
- Fellow CSP enthusiasts: Mike West, Adam Barth, Brad Hill, Devdatta Akhawe, Neil Matatall, Joel Weinberger, Kailas Patel