Why deploying a Content Security Policy helps (for real!)

Mukund Sarma
5 min readApr 15, 2019

I have heard many people in the industry state that the level of effort to deploy Content Security Policy (CSP) is not worth the value it brings. I disagree; it depends on what threat model are you solving for.

This is not yet another post that explains what CSP is. I personally followed Google’s csp.withgoogle.com website and found it helped me deploy a config quickly. Here’s another good resource that links you to blog posts on how companies have deployed this in the past and references to tools such as Mozilla’s Observatory.

Why did I deploy CSP in my organization?

Was it to prevent content injection attacks? Not really. Using 3rd party code helps you ship quickly, but now you are relying on other companies to get their security right. It’s a double edged sword! The number of breaches caused by rogue 3rd party javascript was pretty high in 2018, causing me to wonder where exactly the content we load in our applications comes from. The initial report data from our main application alone was pretty shocking — we had dozens of different content sources, meaning we were betting on dozens of outside development teams to do their security right (which in retrospect feels foolish).

Being able to quantify the risk convinced senior management that it was in our best interest to deploy CSP for all our applications. It also drastically changed how we did our 3rd party vendor reviews.

So, what did I do?

I’m a huge fan of solving a class of vulnerabilities at the framework level and I wanted to bake this into our internal frameworks so that all existing and new applications automatically opted in to using this.

All of this sounds brilliant but in reality setting a good mature policy takes a long time and requires buy-in from Engineering. It means you’re required to work with them on getting used to the fact that we now have CSP and they need to get all new scripts reviewed and approved by Application Security. This can be overwhelming; so I’m going to tell you what you should consider if you’re using CSP to solve for the same threat model.

  • Build developer tools: I think this was the most important step during the whole process. We built pipelines that allowed developers to self-host approved 3rd party javascripts in our own CDN. Having this pipeline ensured that it was easy to self-host and also ensured that Application Security could perform a set of security checks automatically that checked if the script was sane. We forked eslint-plugin-security and added some custom rules that applied to our organization. This ensured that the security team wasn’t the bottleneck and we had to review the javascript only if the linter failed.
  • Build or buy a CSP server and log processor: Depending on your need, you can either end up using cloud/lambda functions for CSP, or if you’re deploying CSP on a dozen of applications on a few hundred servers and plan on consuming the reports, you’ll need a CSP server. Either you build one yourself, or if you’re willing to spend money, use an existing service like Sentry or report-uri for the same. report-uri is affordable, but sentry is more usable (I wish they had a pricing model for just security headers).
  • Deploy Subresource Integrity(SRI) for your assets on the CDN: Do you really want to trust your own CDN provider? I have friends and colleagues who have worked for the top CDN providers and have told me stories of how there is little-to-no physical or infrastructure-level security guarantees around their non-premium products. Since this challenged the integrity of our CDN artifacts, an attacker could inject malicious code that would subsequently run in privileged contexts (e.g. member browser’s) and we wouldn’t know about it. So if you’re as paranoid as me and don’t want to trust your own CDN provider, I highly recommend implementing SRI for all static assets, too. SRI with CSP is ❤
  • Break it down to multiple deploys: I simply did what worked for others. Start off in report-only mode. I didn’t see a point reinventing the wheel here. Every blog post or talk I listened to mentions how this really helped them. Don’t worry about getting the most accurate policy out there in your first attempt but rather get a rough policy out first and then work on making it more mature. It’s something that one needs to constantly modify and isn’t like the rest of the security headers where you set it once and forget about it.
  • Learn your attack surface: Once you have your config in a state where it’s only generating reports for things that matter, take a look at your policy. Go through the list of sources that you’ve whitelisted and come up with ways to classify each of them based on a risk criteria you set.
  • Clean up and reduce your attack surface: This isn’t a one time thing. You need to keep revisiting your list to see how many of these vendors support SRI or a way to self-host it if it makes sense. Some of these scripts aren’t versioned and/or change several times a day. In such situations it makes very little sense to either self-host these scripts or include the SRI hash.
  • Keep an eye for what gets self hosted: Building good pipelines and automation to host these scripts in your CDN definitely helps, but one can potentially misuse it too. I made sure that the Application Security team was added to the Github owners file for CSP configs and thereby we had a way to enforce strong change control on what content actually ends up on our applications. Minified JS files are not readable and one might use this to get to self host assets of vendors that have not been approved by your third party vendor review committee. Make sure you audit what gets pushed to the CDN.
  • Filter out logs from noisy browser extensions: It turns out that people install all kinds of shady browser extensions that try to inject scripts on the client side. This can be really noisy and I highly recommend having a way to filter these out.

Other unforeseen advantages:

  • Deploying strict-csp helps! In reality there’s very little chances you can get rid of all your inline scripts. This is where deploying strict-csp helped. We even got bug bounty reports telling us how CSP was actually preventing content injection attacks! (I wasn’t even trying to solve for that threat model) This control really helped reduce the severity (which means longer SLA’s) for a reflected XSS (for example), thereby giving our engineers more time to fix it. This drastically improved our relationship with our engineers and they are now more willing to add other such security controls. It’s a win-win situation for everyone! \o/
  • It drastically changed how we did our 3rd party vendor reviews. Before we deployed CSP we didn’t account for 3rd party JS includes. Our process didn’t involve us reviewing the vendors JS. It’s sad that the industry hasn’t adopted CSP or SRI as much as we’d like. Very often vendors hear about these controls for the first time because we ask for them to support SRI. Though we’ve had a few vendors that have actually gone back and implemented SRI and thereby making this whole ecosystem safe for everyone, the reality is sometimes it just doesn’t make sense to have SRI.

I have to agree with Scott Helme that Content Security Policy is application security’s Swiss Army Knife. Though it was introduced as a control to prevent content injection, many others and I have used it to for detection capabilities too!

--

--

Mukund Sarma

A curious being! :) I enjoy doing Security stuff and fortunately make my living doing it. The contents I share here are my own and not the views of my employer.