This is the second blog post in the series Hardened Content-Security-Policy where I write about some tips for securing Content-Security-Policy (CSP). Part 1 can be found here.
Static resources should have strict CSP
default 'none'; referrer no-referrer; upgrade-insecure-requests. This policy will not be applied when you embed them, the policy will only be in use when you directly visit them, for example https://example.com/image.jpg
This could protect in some cases where users (or you) can upload just some type of files, but for some reason this protection gets bypassed and an attacker manages to upload "dangerous" files. Even if the worst case scenario happens where an attacker manages to upload an HTML-file, the attack would be very much mitigated due to the strict CSP. Example at Github
CSP in meta right after
If you're using CSP in
<meta> - tags you should have the tag right after
<head>. This is because resources before the
<meta> - tag is not blocked by CSP. This is simply due to the way browsers are rendering HTML, that is from the top to the bottom.
Here's a PoC.
If an attacker would have the possibility to inject HTML before the CSP in meta, the content would not be blocked by CSP.
require-sri-for style script in your CSP, the browser will not load resources (.css & .js) that does not have a correct SRI hash specified.
This could, in some specific situations protect when an attacker only can control the
Go full path, or no path at all
As explained in my previous article Bypassing paths in CSP with open redirects I show that it's possible to bypass paths in CSP with redirects. I've already explained some mitigation in that article but it's worth to mention once again.
So if you're using paths in your CSP, you should use paths even on your origin. This means that you should avoid
'self' and instead use your domain with specified paths to the resource.
This would protect if you're using paths but also
'self' because the chance would increase that the attacker find an open redirect on your domain and use that to bypass all the paths.
If you don't use paths, you can ignore this tip.
EDIT: Patrick Toomey had the idea of avoiding
'self' completely and instead use another origin for user controlled data. That's a great hardening tip!
I've been working with many CSP reports in my short lifetime and can only draw the conclusion that it's very time consuming and the wrong approach.
The main problem with CSP reports is the verbosity. Browsers make a lot of noise with theirs extensions and just overall strange behavior. Another problem is that CSP reports can easily be spoofed and if you don't analyze the reports and find the root cause you may whitelist something that's all based on fake reports, which may introduce bypasses.
Instead, design your website better and have this design applied over everything. For example, you should really avoid
unsafe-inline so even if you have a dynamic CSP or many subdomains with different polices, you should be able to use the same policy. Dynamic CSP is good, but the only thing that's better is a strict global policy - which only can be applied if you correctly design your website.
That's it for this time!