Wednesday, January 22, 2014

Content-Security-Policy, Browser Extensions and JavaScript Templates

A couple of weeks ago I started seeing weird advertisements on some pages. I didn't pay it too much attention, but it was obviously wrong since some ads where displaying even in Youtube (as in, interrupting the Youtube video). Then one day I received this e-mail in my inbox:

This is our automatic e-mail notification of a Content-Security-Policy violation. Apparently I was injecting JavaScript pointing to into my own web page. WTF?

Ads and Trojans in Chrome extensions

Adware vendors have recently been acquiring Chrome Extensions to inject ads while browsing. Widely successful extensions are being sold to shady companies that turn them into trojans, in my case Awesome New Tab Page. These extensions have so many positive reviews that it will take a while for all the 1-star ratings to pull it down, or for Google to notice and drop it from the Chrome Store.

So Content-Security-Policy was saving my page from ads, even when it shouldn't. Chrome extensions are not constrained by Content-Security-Policy violations by design. What would be the point of notifying XSS injections, if everyone with a Chrome or Firefox extension will trigger a false positive? That would be an obvious way to disable AdBlock.

What is Content-Security-Policy?

Content-Security-Policy is the simplest way to restrict the list of allowed JavaScript locations for your site. Just by adding the Content-Security-Policy header you are 90% into a working solution for JavaScript injection attacks.

Why only 90%? There are different ways of including JavaScript code in your web page:

  • External, Embedded or Inlined: this is what CSP is all about. It will constrain the list of valid locations for your JavaScript files, and there are workarounds to pass arguments to your JavaScript code with CSP.
  • eval(). It was evil, right? Like, "friends don't let friends use eval()" evil?

Some libraries like Google Maps are still using eval, but that's considered a bug and should eventually get fixed. This is the real problem:

var s = _.template(
   'Complete ({{numresults}} processed). Your report is <a href="{{url}}">here</a>',
   { numresults: 5, url: '' }

All template implementations use eval under the hoods. Underscore, Lo-dash, Handlebars. Precompiled templates are still safe, but they require a separate file for each template. This is killer for simple cases like i18n messages, so we ended up using our own dumbed-down mustache implementation for this.

JavaScript libraries should not use eval() in order to be used by applications that specify Content-Security-Policy headers.

Content-Security Policy violations

One of the best things of CSP is that you can be proactive about attacks: you don't have to wait until being hacked to do something about it. By enabling CSP reports your admin account will be spammed about suspicious activities, in time to block the user or send him a horse head.

The only problem is that all browser extensions should be left out of the game. Right now support for this is partial: some extensions are still triggering a false positive (like the Awesome Tab Extension above), which renders the feature useless for the time being.

We are really happy with the status of CSP today. We trust more in the security of the system, even if not all browsers support it. It would be great if the notification system didn't send a daily reminder of browser extensions faved by our users, but that will eventually get fixed.

With CSP and mandatory SSL being included in http 2.0, things are definitely improving.


  1. I just wanted to clarify why you're seeing CSP violation report originating from malicious extensions.

    It's not that extensions are not subject to your site CSP at all.The JS code that runs in their isolated world can bypass your CSP (e.g. content script can eval() stuff even if you have no unsafe-eval directive, it can make XHR requests wherever etc.).

    But as soon as they mess with your DOM, it's subject to your CSP. Awesome New Tab extension most likely tried to inject a [script] or [iframe] from external domain and this is what get caught by your CSP, hence the violation report.

  2. Thanks for the clarification! I understand that there is no solution to the current state of things, then: modifications to the DOM done by extensions should still be reported, as they are as much of a security threat as if they were done by the user.

  3. Nacho, if CSP could prevent extensions from modifying your website at all, all webmasters would use CSP to prevent AdBlock from blocking ads. The trendsetters that push browsers to their mom, dad, uncle, grandma, etc., who almost all use AdBlock, would stop using browsers that were that severely flawed.

    CSP isn't designed to combat browser extensions. Any browser that ever does allow websites to block AdBlock (which is what you're essentially asking to be capable of) would quickly become unpopular.

  4. Forget my previous comment, you are right. I checked the latest draft, and browser extensions are indeed considered trusted content, not subject to CSP restrictions. I suppose cases where the extensions are injecting malicious content should be handled elsewhere.


Something on your mind?

Note: Only a member of this blog may post a comment.