Menu

How I learned to stop worrying and love CSPs

Published on by Hidde de Vries in thoughts .

To gain precise control over what styles, scripts and other assets do on your site, you can serve pages with a Content Security-Policy. What does that mean for the front-end, and for those of us building user interfaces in browsers? Well, it can be tricky to set up, but there are useful benefits.

Why CSPs?

CSPs basically work like a whitelist of asset domains that the browser will accept for your site. This is great, as browsers have no notion of benevolent or malicious assets. Only website owners do. By telling browsers where the good stuff is located, website owners can rest assured users of modern browsers won’t get bad assets executed. They are one out of many security headers.

CSPs have been around for ages (see for example the Twitter blog in 2011), but usage numbers seem to be quite low. It seems to me they have recently gained more traction though, as more people get interested into website safety and content integrity. See also how Mozilla Add-Ons did it.

How they work

Technically, a CSP is a string that contains key-value pairs, served as a header with the response (or via a meta element in the page). They describe for each type of content how it can be used within your page. To be more precise: where it can be loaded from. Definitions for each type of asset are separated with semicolons, the definitions themselves have spaces in between.

Here’s an example:

script-src https://hidde-cdn.com; style-src https://hidde-cdn.com

This will only allow scripts or styles if they are served from https://hidde-cdn.com.

There are also a number of keywords.

See for example, this policy:

script-src 'self' https://hidde-cdn.com; style-src 'unsafe-inline' https://hidde-cdn.com

This allows scripts only from the current domain or from https://hidde-cdn.com, and allows styles inline or when served from https://hidde-cdn.com.

There are also directives: font-src for fonts, img-src for images,connect-src for fetching/requests and default-src if you want to set a default. Best set default-src to none, so that you already have a policy for any asset types you don’t or forget to define.

The unsafe-inline directive is interesting: it has the word ‘unsafe’ in it, because inline assets are considered harmful. I should clarify: inline assets aren’t harmful because they are inline as such, but it is the case that whenever malicious scripts or stylesheets are injected, they are likely to be inline. Blocking their execution altogether mitigates their risk. If that feels like too much, it is also possible to allow some inline scripts: identify one script with a nonce (a number used once) and whitelist that nonce.

In summary, a CSP lets you whitelist locations to load assets from. Although these whitelists themselves are simple when you grasp the concept, their consequences can be unexpected and, for front-end devs, rather inconvenient.

Some side-effects

When I recently implemented a CSP in a project I was working on, I found a couple of surprises that were inconvenient, some of them related to disallowing inline assets. Note that those specific issues will be go away if your setup has a different, less stringent CSP locally.

Adding styles via Developer Tools

Sometimes when I’m working on some CSS, I’ll inject CSS via the Dev Tools, so that I can see what the effect of my changes are without actually making them just yet. If your CSP disallows inline styles, you are out of luck as this feature will stop working.

Browsersync

If your local development environment uses script to reload the browser when you’ve changed a file, this likely uses inline scripts that will be blocked when your policy forbids inline scripts.

Analytics

If you’re using external analytics scripts, don’t forget to add the domains that they load from, if they are different from your own domain. This is the case for Google’s Analytics and Tag Manager products, for example.

Polyfills that inject CSS

The inert polyfill injects some CSS into the page in order to prevent user selection on inert elements. Injected CSS counts as inline CSS (obvs), so that will not work.

Inline styles in SVGs

Double-check that SVGs that you are including in your page do not contain style attributes, as some browsers can deem those to be a violation of unsafe-inline.

The good and the bad

What I love about CSPs

The great thing about CSPs is that, if implemented well, you know exactly where to expect attacks. Without a CSP, the ‘attack vector’ is unknown and likely big or of infinite size, with a CSP you know where it can come from.

If you work in a large organisation where the marketing team can insert scripts via Tag Manager(-like) solutions, which is quite common these days, CSPs are also a useful treshold. Scripts that are useful for gaining marketing insights could at the same time be risky from a security standpoint (not to mention privacy).

There are some design choices that make CSPs a joy to work with, for example the built-in report-uri directive, that lets you specify a URL to report CSP violations to, which can be used to track violations using a service like Sentry.

What I slightly dislike

If your site is served over SSL and you sanitise all the things (in other words, you avoid Little Bobby Table scenarios), your CSP does not actually make it more secure. Note that this is a huge if. If you’re healthy, a health insurance isn’t going to make you more healthy, but it is extremely sensible to have one in place anyway. This is kind of the point of CSPs, they provide extra cover for if things like SSL and XSS protection aren’t (correctly) in place. Mistakes can be easy to make in the security space. So I’ve learned to love this: CSPs don’t harm if you can work around the side-effects.

Something else I don’t really like is the usability of error reports for CSP violations in browser Dev Tools. They will make clear that there is an error, but aren’t too helpful in pointing towards the right direction. Browsers could be clearer about which exact bit of your policy is stopping an asset from working.

TL;DR

CSPs can nullify what XSS attackers can do once they’ve managed to attack. This is great, although implementing it can make some things harder on the front-end. But that’s ok, it is our job after all. For help with implementing a CSP for your site, check out Mozilla’s Laboratory Add-On and Google’s Web Fundamentals page on CSP.

Thanks Scott Helme, Jan van Hellemond, Krijn Hoetmer and Tim Severien for feedback on (earlier drafts of) this post.

Comments & mentions (7)

Marc Stalfoort likes this
Bramus! likes this
Bramus! reposted this
Kristof Neirynck likes this
See Guo Lin ⌘ replied: How I learned to stop worrying and love CSPs hiddedevries.nl/en/blog/2018-0…
Jimmy Wilson replied: Great read to start the week - hiddedevries.nl/en/blog/2018-0…
Hidde de Vries replied:

The year is about to end, so it is time for another year in review post! I love reading what others write about their years, hopefully mine is interesting to some people.

Like last year, I’ve divided stuff into highlights and things I learned. To be clear, that doesn’t mean I had a year consisting of 100% highlights and learnings, there is also stuff that went wrong, wasn’t amazing or was personal, I just think they’re for elsewhere (in person over drinks).

Highlights

Projects

In 2018, I spent most of my time in Mozilla’s Open Innovation team, working specifically on the IAM project. For those unfamiliar with it, IAM is short for identity and access management, it is about how people proof who they are and get access to stuff with as little friction as possible. It’s been super exciting to build most of the front-end for a project codenamed “DinoPark”.

In the last quarter, I’ve also spent a day a week working at the City of The Hague, specifically helping with improving accessibility and profesionalising front-end development of their digital services. It’s been great to see improvements shipped both in the application’s code as well as the content management system product.

Other short engagements included:

  • teaming up with Jeroen and Peter, I helped NOS, the Dutch broadcaster, with an accessibility audit, user tests with visually impaired users and an in-house presentation on technical accessibility
  • I ran a one day workshop on accessibility guidelines at Zilveren Kruis
  • with Peter, I worked on JavaScript to power a chat-like interface for the Dutch government

Volunteering

I did not do a lot of volunteering this year, but I did translate the Inclusive Design Principles into Dutch and worked on improving MDN documentation on accessibility.

Conferences and events

This year, I attended these events:

I spoke multiple times, too:

I did my CSS Layout workshop three more times (for Fronteers and at Front-end United) and ran a new accessible components workshop (for Frozen Rockets).

Organisers, thanks so much for having me. The first time conference speaking was stressful, time-consuming and very scary, but also satisfying. I got great feedback, both praise and things I can improve on (thanks, you know who you are).

I’d love to speak more in 2019, please do get in touch if you want to have me present at your event or give a workshop.

Writing

I published 26 posts on this blog, not including this one. Like I said in last year’s review: I very much recommend writing, it can be helpful in many ways. It is also great to be able to do this on a domain you own, on pages you designed. If anyone needs mentoring around this, get in touch, I would love to help!

Some of the most read posts:

Reading

It felt a bit weird to have the Goodreads app keep me in check reading-wise, but it did the job. I managed to read more than the goal I set. Some that readers of this blog might find interesting:

Book covers of brotopia, klont, common sense and killing commendatore
  • Brotopia, about the ‘bros’ that founded some of the biggest Sillicon Valley corporations and the culture they created. I must admit some doubts towards the word ‘bro’ , but wow, the book taught me a lot about how I don’t want to be and where I don’t want to work.
  • Klont – if you read Dutch, get it! This novel brilliantly captures the phenomenon ‘datafication’ and how it endangers some of the basic concepts of free societies, as well as, unrelated, the phenomenon of ‘experts’ traveling the world to give talks
  • Common sense, the Turing test and the quest for real AI – sometimes fairly technical and academic, but I loved the hype-free thinking about artifical intelligence and what to expect from it
  • Killing Commendatore – if you’re into Murakami or want to start reading his work, this is great. It is a lot of pages, in two parts, but worthwile. I read the Dutch translation, it is available in many other languages, too.

For all the ‘big data’ and AI expertise that Amazon, which owns Goodreads, has, the app is still very bad at recommending new books. For me, it doesn’t go beyond what the most generic airport bookshops stock. The real human beings I have befriended there brought much more reading inspiration.

Things I learned

Some random things I learned:

  • I finally got my hands dirty in declarative client-side component frameworks. My framework of choice was Vue.JS. I learned concepts like routers, props down / events up, reactivity and lifecycle hooks, enjoyed working in this paradigm, but even within that, I mostly wrote just JavaScript, good markup and sensible CSS. I have a blog post upcoming on this.
  • I learned in multiple projects this year how hard it can be to explain the concept of focus. It exists as a thing in the browser (the document.activeElement), but also as a thing in people’s thinking, not necessarily the same way. And then I’m not even talking about indicating focus yet. In my talk in Groningen I spent a number of slides trying to get it crystal clear. I like Laura Carvajals “You wouldn’t steal their cursor” and tried a streetlights metaphor (they are not pretty, but if they’re not there, you can’t see where you’re going at night)
  • I worked with WCAG 2.1 in real projects (testing for the newly added success criteria and talking about them in slides)
  • I added CSPs to some sites (see also How I learned to stop worrying and love CSPs)
  • I did more background reading to better understand the world we’re developing front-ends for (super meta), inspired by various colleagues, conference speakers and friends

What I want to get better at next year:

  • writing and presenting
  • I want to try and build something with Rust
  • get more people excited about having a personal website with a blog

With that, I wish all readers a fantastic 2019! If anyone has written year in review posts, I’d love to hear about them in the comments/webmentions, and read what you have done.

Leave a comment
Posted a response to this?

This website uses Webmentions. You can manually notify me if you have posted a response, by entering the URL below.