Content Security Policy update

A quick update about CSP. Browsers are well on their way to all adopt the specification.

An early draft was already adopted by Firefox 4, and I just found out that it's also working in Chrome, Safari and IE 10.

IE10 and FF are using the following header:

  1. X-Content-Security-Policy: default-src 'self'

While Safari and Chrome use:

  1. X-Webkit-CSP: default-src 'self'

When the specification is finalized, the X- will be dropped, and it will simply be 'Content-Security-Policy'.

A call for support

Hi Developers! Start implementing this feature! It's important for the future and security of the web. The web's biggest vulnerability, from what I understand, is still XSS, but if people start to properly implement CSP, XSS can effectively be a thing from the past.

So even if you don't want to risk using CSP on a production environment, at least consider adding the headers in your development environment. It will force you to write better code, by not embedding javascript directly into the HTML source. By considering this right now, you will also make it much easier if you do decide to adopt CSP at some point in the future.

I'm implementing CSP full-on in a new project, and one of the things I've noticed already is that some of the javascript we embed from 3rd parties use eval() and inline html events (onclick & friends). For the sake of security we will most likely decide to only use 3rd party code if they are indeed CSP-compatible.

Content Security Policy introduction

I blogged about Content Security Policy about 2 year ago when it was still called 'Site Security Policy'. It started as a specification and an add-on, and turned into a patch a bit later. Finally it made it into Firefox 4 beta 1. I think CSP is the next web security revolution, so make yourself aware of how it works and the implications.

So what is it? The short version is that it's a very effective measure against cross-site scripting. By specifying a policy through the 'X-Content-Security-Policy', you can specify exactly from which locations you accept javascript and other content. This allows you to block scripts from any domains unknown to you, and inline scripts altogether.

A simple example

  1. X-Content-Security-Policy: allow 'self'

A simple PHP example to see this in action:

  1. <?php
  2.  
  3. header("X-Content-Security-Policy: allow 'self'");
  4.  
  5. ?>
  6. <html>
  7. <head>
  8. <title>CSP test</title>
  9. </head>
  10. <body>
  11.  
  12. <script type="text/javascript">
  13.  
  14. alert('XSS!');
  15.  
  16. </script>
  17.  
  18. </body>
  19. </html>

If the above code is opened in Firefox 4.0 beta1, the script will not execute, and a warning is added to the "Error Console" (in the Tools menu).

Not only does this header block inline scripts, it also blocks the following:

  • eval(). This important for people using eval() to parse json responses.
  • setTimeout and setInterval if the function is provided as a string.
  • javascript: urls
  • HTML event attributes (onclick, onload, etc.).
  • All images, plugin objects (flash, quicktime etc.), audio, video, html frames and fonts not served from the same domain as the html page.
  • XMLHttpRequest to domains other than the source domain.

Fortunately there are fine grained controls about what you want to allow from which domains. Here are some examples from the specification.

  1. X-Content-Security-Policy: allow 'self'; img-src *; \
  2. object-src media1.com media2.com *.cdn.com; \
  3. script-src trustedscripts.example.com

This example starts with "allow 'self'", allowing only content from the same domain. The "img-src *" rule allows images from any domain. "object-src: media1.com media2.com" allows <object> tags to use files from media1.com, media1.com and the same domain as the html was served from. To learn more about these, I would recommend just taking a good look at the directives list in the specification.

Options and reporting

Using the 'options' directive it's possible to turn on specific measures. Valid values for options are 'eval-script' and 'inline-script'.

  1. X-Content-Security-Policy: allow 'self'; options inline-script, eval-script

The preceding example allows inline scripts (using html event attributes, or the script tag) as well as the 'eval()' function. In general I would try to avoid this though.

When a security rule is violated, it's possible to get the browser to send a report back to the server. For example, if an image is referenced from a blocked domain, the browser can send a simple report to a url you specify.

  1. X-Content-Security-Policy: allow 'self'; report-uri http://example.org/cspreport.php

This allows you to detect any problems with your policy, or successful attempts by your evil users to inject code. An example of such a report is the following:

  1. {
  2. "csp-report":
  3. {
  4. "request": "GET http://index.html HTTP/1.1",
  5. "request-headers": "Host: example.com
  6. User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.3a5pre) Gecko/20100601 Minefield/3.7a5pre
  7. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  8. Accept-Language: en-us,en;q=0.5
  9. Accept-Encoding: gzip,deflate
  10. Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  11. Keep-Alive: 115
  12. Connection: keep-alive",
  13. "blocked-uri": "http://evil.com/some_image.png",
  14. "violated-directive": "img-src 'self'",
  15. "original-policy": "allow 'none'; img-src *, allow 'self'; img-src 'self'"
  16. }
  17. }

Final notes

Using CSP does not mean you can go easy on other security measures. At the moment a very limited amount of users will have support for CSP, so everybody else still needs to be protected. However, it's still a great idea to implement. Your Firefox users will automatically be protected better, and because of the reporting functionality, they automatically help you detect holes which benefits everybody.

My guess is that CSP is going to be very important, and is here to stay. There are two things you can do to prepare for the future:

  1. Figure out your policy. It's a good idea for your web application to know anyway where resources are coming from. Especially advertisers tend to be bad at using many different domains and scripts using other scripts.
  2. Try to avoid any inline scripting, html event handlers and eval(). They are all avoidable, and in my opinion it is a good idea to keep your javascript out of html anyway. This is a big one, because both inline scripts and html events are still very popular. With the popularity of libraries such as jQuery, I do think it will be easier to just grab most of the inline scripts and move them to an external script.
 1

About

My name is Evert, and I've been writing semi-regularly on this blog since 2006.

I'm currently available for contract work.

more info.

Subscribe

Dropbox

Dropbox is a simple cross-platform online backup and sync application. The first 2GB of space is free, and both you and me get an extra 250MB extra space if you sign up through this link.