Here at SendSafely, we’ve advocated the use of Content Security Policy and have been running a fairly strict CSP in block mode for over a year now. With the release of Google Chrome version 40 this week, we wanted to highlight one important breaking change that resulted in the need for us to adapt our CSP to work with the new version of Chrome.
Chrome has always been an early adopter of CSP, and version 40 is the first major browser to bring support for the new CSP Level 2 specification. Unfortunately, sites that implement CSP1 and are not prepared to support CSP2 may start to encounter some false positives as a result of this change. For sites like ours that run in block mode, this could have a major impact as it may prevent certain pages from running.
We use CSP Violation Reports to track when our policy blocks attempts to load content from users on our site. About a month ago we started seeing some interesting violation reports during our normal log review. Specifically we were seeing reports where the violated-directive: default-src ‘none’ and blocked-uri: values of the JS files were located in our /js/workers/ folder. This was highly unusual, because while we usually receive a good number of CSP violation reports every day, they normally have some telltale false positive indicators. Specifically they usually don’t point back to blocked-uri values that actually exist in our application. In these cases, those signs were absent. Our investigation of these errors showed a common thread across these reports: the user agent string (Chrome/40).
The error reports started rolling in just a few days after the v40 Beta was released (December 4, 2014). We use BrowserStack for most of our pre-release browser acceptance testing, so we always have easy access to the latest Beta and Dev version of Chrome for testing. When we tested with v40 Beta, we quickly saw that our code which spawns HTML5 web worker threads were being blocked by Chrome due to a violation of the new CSP2 directive that was undefined in our policy. Our application relies on Web Workers for encryption and decryption within our HTML5 UI, so this is a critical function needed for encrypting and decrypting files transferred through our site.
The CSP2 spec adds several new directives that allow for more granular security policies. One of these directives, child-src, is the one that proved to be problematic for us. The child-src directive is designed, among other things, to control the source from which a page can load HTML5 Web Workers. In CSP1, Web Workers were controlled through the script-src directive (which basically controls where any JavaScript files can be loaded from). With Chrome v40, this means that sites using a strict CSP with default-src 'none’ (like ours) will have web workers blocked by default unless you explicitly allow them using the child-src directive. Fortunately, the fix for us was easy…we just needed to add a child-src directive and that did the trick. That being said, we’ve certainly never seen such a breaking change happen to us in a single browser release.
We were also surprised to find that the Chrome release notes did not warn about the potential impact of this change, aside from a small footnote in the release notes for the v40 Beta noting “This release brings support for the new directives introduced in Content Security Policy (CSP) Level 2”. The low profile of this feature is likely a result of the relatively low adoption of CSP in the wild. One thing to note is that as of today, Chrome is the only major browser to support the new CSP2 directives, which means that other browsers will throw some nasty console errors if you include them in your CSP. Both Safari and Firefox will show errors similar to the one below:
From our testing these errors do not impact our site’s functionality, and web workers are still protected by the script-src directive for unsupported browsers. We will, however, have to live with this error until more browsers pick up the new standard (or deploy a Chrome-specific CSP, which we’ve opted not to do for now). For those that have followed the evolution of CSP, this almost feels like a flashback to the early days of CSP when there were numerous browser-specific nuances and quirks that plagued initial support across the major browser vendors. Luckily it seems like we have found a policy that, at least for now, works well with all major browsers.
Now that Chrome supports CSP2, we will begin the process of moving forward with our migration plan to a more granular CSP policy. Stay tuned for a new blog post outlining the changes we’ll be making to take full advantage of the new CSP2 spec.