Content Security Policy Demystified

Content Security Policy is low-hanging fruit for your website's security.

Just a single line gives us complete control over which resources can be downloaded (and possibly executed) from where. Yes, it might look a bit cryptic for an untrained eye, but it's in fact, very straightforward.

Using it wisely is a simple way to mitigate certain types of attacks like Cross Site Scripting, Form Hijacking, and the Packet Sniffing Attack.

If you have never heard about those, please take your time and make yourself familiar.

No, it's not boring.

How to use it?

There are two ways to set up a CSP policy:

  1. As a response header Content-Security-Policy: YOUR_POLICY
  2. As a meta tag <meta http-equiv="Content-Security-Policy" content="YOUR_POLICY">

The policy itself looks the same in both cases.

An example

Let's start by looking at a simple example.

default-src 'self' *; img-src *; script-src 'unsafe-inline'; img-src;

With CSP, we define a set of rules per each resource type, and those rules are separated with a semicolon.

  1. default-src 'self' * is the policy that works by default for anything we don't mention specifically. In this case, we allow to fetch resources from the current domain (self) plus all of the subdomains of

  2. script-src 'unsafe-inline' When it comes to scripts, we allow them to only load from the domain. No others will be allowed.

  3. 'unsafe-inline' allows for executing inline scripts (that is scripts inside <script>...</script>). By default, those are not allowed, and for a good reason. But sometimes, you might want to allow it.

  4. Finally, we allow images to only be downloaded from a CDN with img-src

The structure of a CSP

Now that we've seen an example, it's easy to see a pattern.

<directive> <source1> <source2> ...; <directive> <source1> <source2> ...; ... 

A directive is usually some resource type.

  • script-src define rules for scripts
  • style-src for styles
  • font-src, you guessed it
  • and many others

The default-src directive, as mentioned above, is a special kind of directive which defines the default rules for the resources we haven't specified directly to fall back to.

The sources are mostly places from which the particular resource can be fetched.

  • 'self' means the current domain excluding the subdomains
  • * means "from anywhere"
  • https: means "from anywhere as long as it's using TLS" (note the last colon - it's mandatory)
  • a specific domain
  • subdomains of a specific domain *
  • and there are more.

Some of the directives can be used with special sources.

For example, the already mentioned unsafe-inline (allowing to execute of inline code or applying inline styles) makes sense for styles and scripts, but not for fonts.

More Examples

Let's look at some practical examples.

  1. default-src 'self'

Simple and elegant. Allow loading all the resources only from the current domain. The inline scripts and styles are not allowed.

  1. default-src 'self'; style-src 'self'; img-src 'self'

Allow loading images and stylesheets from a CDN.

  1. default-src 'self'; form-action: 'self'

Forbid any form actions other than the current domain. Note that for some reason, form-action doesn't fallback to default-src, so we have to set it specifically.

  1. default-src 'self'; report-uri;

Finally, browsers can notify you by sending a report anytime a violation occurs.

It's handy to know if your website is working correctly for everyone or if someone's trying to hack you or your users.

Then it is your job as a developer to make sure that /csp/report endpoint can accept and store the reports. To learn more, read here.

Further reading

I hope this article helped you understand how the CSP works and encouraged you to use it today as it is so simple and powerful.

Here are some links for you to dive deeper.

🔥 100+ questions with answers
🔥 50+ exercises with solutions
🔥 ECMAScript 2023
🔥 PDF & ePUB