I often get both of these concepts confused, and apparently so do a lot of other people. It's a pretty important concept to be understood by web developers and security engineers, so hopefully this clears things up.
Cross Origin Resource Sharing (CORS) and Content Security Policy (CSP) are used by web applications to control what data can be loaded on a page, and what data other pages can load from it (see, it's already gotten confusing). It is vital to have CORS and CSP configured correctly from a security perspective, because it would otherwise be difficult to trust the integrity of a web page (if any scripts can be loaded) but also the confidentiality of your own data on a web page if it can be loaded by anyone.
When learning about CORS and CSP, it's important to understand what's going on from both perspectives (requestor and requestee), because as a host you will be playing both positions. To drive this message home, I'll be referring to YOUR website which is ✨Super Secure Sally✨, and MY website which is 🤡Really Risky Ricky🤡.
To quote MDN Web Docs
"Cross-Origin Resource Sharing (CORS) is a HTTP-header based mechanism that allows a server to indicate any origins other than its own from which a browser should permit loading of resources."
You can view what CORS policies are set on a particular host/page by viewing the response headers. The main header we are concerned with is:
This response header dictates which domains are allowed to receive the requested data.
Before making a request from another origin, it's common to make a preflight OPTIONS request to determine whether the request will be successful. In that case, the requestor will provide the request headers:
This requestee will then send a response as to which origins, methods and headers are allowed when requesting the resource:
Let's explore this using examples.
Sally (you) wish to load a resource on Ricky's domain. Luckily, Ricky has very relaxed CORS settings and will allow anyone to request resources.
Access-Control-Allow-Origin header contains a wildcard value
* which means anyone can load this resource from his website. This is a super dangerous setting to have, especially if the data is sensitive and confidential.
Ricky wants to now load a resource from Sally. Sally's data is extremely confidential and the most secure CORS settings have been configured to ensure only she can make requests for that data.
Say if Sally changed her mind and she wanted Ricky to be able to successfully request data from Sally. In that case Sally's response header should say:
When it comes to CORS, you want to be conscious of what resources you can load, and what resources other people can load from you.
The goal of CSP is to protect against Cross-Site Scripting (XSS) attacks by dictating which scripts should be trusted and which shouldn't. When a browser tries to run a script from an unknown source, CSP will block it unless it is on the list of trusted sources. If no CSP is provided, then a site will default to using the "Same-Origin Policy" (SOP).
Content-Security-Policy response header contains rules for that request. The CSP can restrict things like:
default-src: the fallback for all resources being loaded if no other rule is set.
script-src: restricts which inline scripts can be run.
style-src: restricts inline styles from being applied.
media-src: restricts audio and media files from being loaded.
img-src: restricts which images can be loaded.
There are plenty of other options to use. You can see them on this Mozilla Developer Page.
At this point, I'm going to introduce a new site 😈 Evil Eddie 😈.
For each of our scenarios, Eddie is going to intercept a request/response to Sally and Ricky's website and try and inject an evil script off his website onto Sally/Ricky's webpages so that it executes the malicious script.
Sally's CSP header looks like this:
Content-Security-Policy: default-src 'self' charlies-cookies.com.
When Eddie tries to attack Sally's website, his script is not loaded because it is blocked by Sally's CSP which says only scripts from her website and her friend Charlie's website will be loaded.
Ricky's CSP header looks like this:
Content-Security-Policy: default-src 'self'; script-src *; img-src *.ricky.com
Eddies attack is successful on Ricky's page, because Ricky has used the wildcard
* character which allows scripts to be loaded from all origins.
Be careful with listing which sites your website can load resources from and only update your allow-list if it's really REALLY necessary. It's also super important to chose resources from secure sites that wouldn't be susceptible to XSS attacks themselves.
Yeah look.. they can be confusing concepts to distinguish because there seems to be a lot of overlap. The way I look at it (in order to help separate the two in my brain) is to consider "what do you have control over". As a host, there are three (general) scenarios:
- You want to request a resource from another site ~ What CORS policies do they have in place?
- Another site wants to request a resource from your site ~ what CORS policies do you have in place?
- You want to load a resource (script, image, whatever) from another site ~ does your Content Security Policy allow you to load resources from that domain?
Have you got any handy ways of remembering the difference between CSP and CORS? I'd love to hear them.