Shameless plug to a library that'll help with CSP and other security headers if you use PHP :) SecureHeaders.
Please please please do not use unsafe-inline for scripts (unless*), it completely bypasses any XSS protection you might hope to achieve. unsafe-inline in style isn't great either.
(*unless) unsafe-inline is okay if you use if for compatibility purposes: providing a nonce-* or hash (e.g. sha256-*) will disable the effect of unsafe-inline in browsers that support CSP2 (almost everyone these days).
For extra points, consider using strict-dynamic in your script policy to disable the script whitelist (on CSP3 compatible browsers) – strict-dynamic will only permit nonced or hashed scripts to run, but will allow them to "bootload" other scripts from other origins. This get's around the problem of an attacker bypassing your CSP via a domain you whitelist if that domain allows user hosted content/has reflection endpoints.
A good whitelist can be stronger than using strict-dynamic, however this is hard to get right. Not using a whitelist for scripts is generally a good idea because whitelists tend to be too permissive in practice: Google research, which found bypasses in 94.72% of distinct observed CSP policies.
For additional extra points, specify two CSPs (multiple CSPs permit only resources that are allowed by all of them): one CSP with strict-dynamic in it, the other CSP with a whitelist – this will only allow strict-dynamic type requests to be made the whitelisted domains. This is the best of both worlds :D
Once you've settled on a CSP, strongly consider running it though Google's CSP Evaluator, which will do a good job a pointing out any shortcomings, including missing (but important directives: e.g. don't forget to specify object-src 'none' – this doesn't inherit from default-src). It'll also point out any known bypasses that occur due to your whitelisted domains.
I am a software engineer focused on Building Teams, Project Management, Software Architecture, C#, .NET Core, Blazor, JavaScript, TypeScript, Azure, User Experience, Web Security, and Performance.
Thanks for reading & taking time to give an excellent reply. Those are all excellent points & I hope people give them a try after getting a basic CSP setup & working. I personally did not know about using two CSPs. I will for sure give that a test.
We need a lot more a lot more CSP fans so fellow developers & frameworks start coding with CSP & security in mind. The biggest hurdle I am currently finding is getting CSP to work with large open source frameworks that change JavaScript on build or inject JavaScript & CSS styles.
The biggest hurdle I am currently finding is getting CSP to work with large open source frameworks that change JavaScript on build or inject JavaScript & CSS styles.
For scripts, can 'strict-dynamic' help? It'll permit even non-external scripts being added into the document by nonced/hashed scripts so-long as they are not "parser inserted". e.g. a nonced script would be permitted to insert a script into the DOM via something like document.head.appendChild (but not via document.write).
For styles (and perhaps some particular scripts) 'unsafe-hashed-attributes' in scripts and style may be worth looking into (once it's finished). The idea is to allow things like:
<divstyle="color:red"onclick="foobar()"></div>
to be compatible with CSP (provided you know ahead of time what the attribute will be). I believe the current proposal is to hash the content of the attribute, so something like <img onerror="foobar()"> would have the same script hash as above (even though the attribute and element is different). For this reason it'll be possible to abuse these in certain situations e.g. consider if the following were legitimate code on the page, whitelisted by attribute
<aonclick="deleteAccount()">Delete account</a>
An attacker could then inject
<imgsrc=#onerror="deleteAccount()"/>
and have it execute on pageload.
That said, having to "be careful" with 'unsafe-hashed-attributes' is certainly a preferable approach to 'unsafe-inline', which essentially says "run all the things" :)
I am a software engineer focused on Building Teams, Project Management, Software Architecture, C#, .NET Core, Blazor, JavaScript, TypeScript, Azure, User Experience, Web Security, and Performance.
Using strict-dynamic is an excellent choice when possible. It is something I should investigate closer. A lot of my front ends are static sites, so that brings some challenges there.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
CSP fan here :)
Some additional notes:
Shameless plug to a library that'll help with CSP and other security headers if you use PHP :) SecureHeaders.
Please please please do not use
unsafe-inline
for scripts (unless*), it completely bypasses any XSS protection you might hope to achieve.unsafe-inline
in style isn't great either.(*unless)
unsafe-inline
is okay if you use if for compatibility purposes: providing anonce-*
or hash (e.g.sha256-*
) will disable the effect ofunsafe-inline
in browsers that support CSP2 (almost everyone these days).For extra points, consider using
strict-dynamic
in your script policy to disable the script whitelist (on CSP3 compatible browsers) –strict-dynamic
will only permit nonced or hashed scripts to run, but will allow them to "bootload" other scripts from other origins. This get's around the problem of an attacker bypassing your CSP via a domain you whitelist if that domain allows user hosted content/has reflection endpoints.A good whitelist can be stronger than using
strict-dynamic
, however this is hard to get right. Not using a whitelist for scripts is generally a good idea because whitelists tend to be too permissive in practice: Google research, which found bypasses in 94.72% of distinct observed CSP policies.For additional extra points, specify two CSPs (multiple CSPs permit only resources that are allowed by all of them): one CSP with
strict-dynamic
in it, the other CSP with a whitelist – this will only allowstrict-dynamic
type requests to be made the whitelisted domains. This is the best of both worlds :DOnce you've settled on a CSP, strongly consider running it though Google's CSP Evaluator, which will do a good job a pointing out any shortcomings, including missing (but important directives: e.g. don't forget to specify
object-src 'none'
– this doesn't inherit fromdefault-src
). It'll also point out any known bypasses that occur due to your whitelisted domains.Thanks for reading & taking time to give an excellent reply. Those are all excellent points & I hope people give them a try after getting a basic CSP setup & working. I personally did not know about using two CSPs. I will for sure give that a test.
We need a lot more a lot more CSP fans so fellow developers & frameworks start coding with CSP & security in mind. The biggest hurdle I am currently finding is getting CSP to work with large open source frameworks that change JavaScript on build or inject JavaScript & CSS styles.
For scripts, can
'strict-dynamic'
help? It'll permit even non-external scripts being added into the document by nonced/hashed scripts so-long as they are not "parser inserted". e.g. a nonced script would be permitted to insert a script into the DOM via something likedocument.head.appendChild
(but not viadocument.write
).For styles (and perhaps some particular scripts)
'unsafe-hashed-attributes'
in scripts and style may be worth looking into (once it's finished). The idea is to allow things like:to be compatible with CSP (provided you know ahead of time what the attribute will be). I believe the current proposal is to hash the content of the attribute, so something like
<img onerror="foobar()">
would have the same script hash as above (even though the attribute and element is different). For this reason it'll be possible to abuse these in certain situations e.g. consider if the following were legitimate code on the page, whitelisted by attributeAn attacker could then inject
and have it execute on pageload.
That said, having to "be careful" with
'unsafe-hashed-attributes'
is certainly a preferable approach to'unsafe-inline'
, which essentially says "run all the things" :)Using strict-dynamic is an excellent choice when possible. It is something I should investigate closer. A lot of my front ends are static sites, so that brings some challenges there.