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 ads.panoramtech.com 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:

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: 'http://foo.bar' }
);

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.