Frontend Security: Content Security Policy
Tags: html, javascript, security
Published: 2021-01-25 07:43:42

In my [previous article on security](https://dev.to/madsstoumann/frontend-security-npm-audit-and-script-integrity-kl3), I wrote about `npm audit` and script integrity. Next up is *Content Security Policy*, or *CSP* for short. 

This can either be added as response-headers on the server, or as a `<meta>`-tag in the html. 

I'm going to focus on the latter here. 

A CSP will tell the webpage from which domains it will allow loading images, fonts, iframes, scripts etc. from: 

```html
<meta http-equiv="Content-Security-Policy" content="
  default-src;
  script-src 'self';
  style-src 'self';
  img-src 'self' data:;
  font-src;
  connect-src 'self';
  media-src 'self';
  object-src 'none';
  child-src;
  frame-src;
  form-action;
  base-uri;
  manifest-src 'self';
">
```

It's *one long string* within the double quotes, so I've added line-breaks and tabs for clarity.  
Each entry ends with a semicolon `;`

Note the word 'self'. That's how you allow to run the various types from the same domain as the current document.

## Scripts
To allow a script from an external site, maybe a delivery network such as *unpkg.com*, add `unpkg.com` to the `script-src`-part of the CSP:

```html
script-src 'self' unpkg.com;
```

Cloudflare provides edge-caching and/or minification for assets, as well as a "Rocket Loader™", which will improve the paint-time for sites using JavsScript. I use it on my sites, but had to add this to my CSP:

```html
script-src 'self' ajax.cloudflare.com;
```

A new entry is just a space, so combined, the current `script-src` looks like this:

```html
script-src 'self' unpkg.com ajax.cloudflare.com;
```

---

## Google Fonts
For Google Fonts, you'll have to add entries to both `font-src` and `style-src`:

```html
font-src fonts.gstatic.com;
style-src 'self' fonts.googleapis.com ;
```
---

## YouTube

For YouTube, you need entries to `frame-src` since it's iframe-based **and** to `img-src` as it provides thumbnail images as well. CSP is not always easy, but it's the quickest way to add an extra layer of protection to your site!

```html
frame-src *.youtube.com;
img-src 'self' img.youtube.com data:;
```

If you include the YouTube API as well, you must add it to the `script-src`:

```html
script-src *.youtube.com;
```

YouTube-videos works with these additions, but will occasionally generate errors for it's "doubleclick"-network and others. You can just ignore these, or add them to your CSP (if you trust them!):

```html
script-src: https://www.googleadservices.com https://googleads.g.doubleclick.net https://www.google.com
img-src: https://www.google.com
frame-src: https://bid.g.doubleclick.net
```

---

## Vimeo
Vimeo just need the `frame-src`:

```html
frame-src: *.vimeo.com
```

But if you want to use their API, add an entry to `script-src` as well:

```html
script-src: *.vimeo.com
```

---
## Warning: Marketeers and SEO-people *hate* CSP's! 
 
With a CSP in place, marketeers can no longer just add a cool new tracking-script via *Google Tag Manager* or similar. So: be prepared to hear **a lot of complaints**, unless you create a CMS-block, where they can add/remove CSP entries themselves!

*Google Chrome* supports many more CSP-entries than listed above. Unfortunately most of these doesn't work in *Apple Safari*, and can actually cause it to *not* parse JavaScript, so be sure to test in *all* browsers.

More info here:

[https://content-security-policy.com/](https://content-security-policy.com/)

And to help you create one:

[https://report-uri.com/home/generate](https://report-uri.com/home/generate)

## Bonus: Add preconnect
While you're adding entries to your CSP, add a `<link rel="preconnect">`-tag for the same entries to speed up communication between your site and these resources. 

*Example for "Google Fonts":*
```html
<link rel="preconnect" href="https://fonts.gstatic.com">
```

Thanks for reading!