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:
- As a response header
- As a meta tag
<meta http-equiv="Content-Security-Policy" content="YOUR_POLICY">
The policy itself looks the same in both cases.
Let's start by looking at a simple example.
default-src 'self' *.mywebsite.org; img-src *; script-src userscripts.example.com 'unsafe-inline'; img-src cdn.example.com;
With CSP, we define a set of rules per each resource type, and those rules are separated with a semicolon.
default-src 'self' *.mywebsite.orgis 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
script-src userscripts.example.com 'unsafe-inline'When it comes to scripts, we allow them to only load from the
userscripts.example.comdomain. No others will be allowed.
'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.
Finally, we allow images to only be downloaded from a CDN with
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-srcdefine rules for scripts
font-src, you guessed it
- and many others
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.
Let's look at some practical examples.
Simple and elegant. Allow loading all the resources only from the current domain. The inline scripts and styles are not allowed.
default-src 'self'; style-src 'self' cdn.mywebsite.com; img-src 'self' cdn.mywebsite.com
Allow loading images and stylesheets from a CDN.
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.
default-src 'self'; report-uri https://mywebsite.com/csp/report;
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.
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 React Hook From Scratch