Why is 'unsafe-inline' unsafe in a Content Security Policy?
What's wrong with inline scripts? is it just unsafe comparing to providing a hash or a nonce? or is there something I'm missing about embedding inline scripts instead of remote scripts?
Inline scripts are unsafe because of XSS. When allowing 'unsafe-inline' you whitelist your own inline scripts as well as any maliciously embedded script. With hash or nonce you can whitelist your own scripts while blocking all other scripts from executing.
Related
I use the Webflow tool to set up my website. I export the code to host it on my server.
I have set up the Content-Security-Policy header.
Problem : most of the styles are inline. I can't add the hash for all of them, there are too many ...
Is it so dangerous to put unsafe inline on style-src ?
Note that this is a 99.9% static site (just a contact form).
Thank you for your help!
The dangers of 'unsafe-inline' in style-src are discussed here: https://scotthelme.co.uk/can-you-get-pwned-with-css/
If you can restrict the rest of your CSP, the dangers will be limited, but there will always be someone who disagrees. If it is technically possible you could use nonces, as you could use the same nonce for all tags, but change it on every pageload. It seems like you don't want or can extract all the CSS to a separate file, which would of course be the simplest solution.
I am trying to understand how Content Security Policies can mitigate XSS-Attacks on Web-Servers. Suppose there is a XSS-vulnerability in an User-Input-Field. It can be used to induce Javascript, such as alert(1) but it can also induce much more serious input, such as a script to exfiltrate Cookies.
When i tried to implement a Content-Security-Policy on that Webserver, i have noticed that both
script-src 'self'
as well as
script-src 'unsafe-inline'
prevent the Cookie exfiltration, however 'self' also prevents alert(1) and unsafe-inline doesnt
I am not an expert to Web Engineering, so i do not know what inline or self even refers to. What do they refer to and what are the similarities and differences between the two and how does that relate to the results i got, when i tried to secure my webserver?
'self' is just a mnemonic (token) for self domain of website.
For example, the website is accessible as http://example.com, http://www.example.com, https://example.com, https://www.example.com. http://example.com:8080 etc.
Therefore you have to specify all these host-sources in the script-src directive, because you do not know via which URL user will access your website.
Alternatively you can just specify 'self', it will mean:
if user access webpage as http://www.example.com, browser will substitute this source instead of 'self'.
if user access webpage as http://example.com:81, browser will substitute this source instead of 'self'.
Note that it's better to have relative Urls in the HTML for 'self' token usage. If user acces webpage as http://www.example.com and in HTML code is using <script src='http://example.com/js/jquery.min.js'> - the script loading will be blocked.
In the connect-src directive the 'self' token additionally allows ws://example.com and wss://example.com in the CSP3-compatible browsers.
'self' is safe because it does not allow XSS via injection of inline scripts or third-party scripts.
'unsafe-inline' it's just a token which allows 3 kinds of inline scripts in the webpage.
'unsafe-inline' is unsafe because it allows XSS through script injection.
I am trying to use a hash with my content security policy...
Below are two example errors in my console:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' apis.google.com cdn.iubenda.com cdnjs.cloudflare.com www.googletagmanager.com". Either the 'unsafe-inline' keyword, a hash ('sha256-oKmCrr+GWRARSXYeVJshOWETr0oqOtt73CNO8efpujQ='), or a nonce ('nonce-...') is required to enable inline execution.
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' apis.google.com cdn.iubenda.com cdnjs.cloudflare.com www.googletagmanager.com". Either the 'unsafe-inline' keyword, a hash ('sha256-pS4Uy3ilo+JLn8IadtJGfyO9z7jqIrGUONfEUDLxoPk='), or a nonce ('nonce-...') is required to enable inline execution.
Here is the corresponding content security policy directive:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' apis.google.com cdn.iubenda.com cdnjs.cloudflare.com www.googletagmanager.com; style-src 'self' fonts.googleapis.com; img-src 'self' cdn.shortpixel.ai secure.gravatar.com; font-src 'self' fonts.googleapis.com fonts.gstatic.com";
Specifically in this example:
script-src 'self' apis.google.com cdn.iubenda.com cdnjs.cloudflare.com www.googletagmanager.com;
From what I gathered from reading the CSP guide on hashes, I should be able to add the hash as per my console to the directive...
The easiest way to generate it is to just open the developer tools console and it will output what the expected hash of your script was in the console error message.
But if I modify my directive to include the hash (example below), I still get the same error in console (obviously with a different hash).
script-src 'self' apis.google.com cdn.iubenda.com cdnjs.cloudflare.com www.googletagmanager.com 'sha256-oKmCrr+GWRARSXYeVJshOWETr0oqOtt73CNO8efpujQ=';
How exactly is the correct way to hash a CSP directive? And why are there multiple errors for the same directive, is this basically one for each domain specified? Should one hash cover all the domains specified?
Not really sure how I should be doing this.
From what I gathered from reading the
content-security-policy.com/hash/ CSP guide on hashes, I should be
able to add the hash as per my console to the directive...
Yeah, it's working only "theoretically", the "practice" is more hard. Yes, Google Chrome calcs hashes, but you need to read the error message carefully to determine what is really blocked: inline script, javascript: navigation or inline event handler. Because each of these have own way how to fix.
- Inline scripts can be just allowed by 'sha256-VALUE' token.
- to allow javascript: navigation and inline event handlers you need to use 'sha256-VALUE' tokens with 'unsafe-hashes'. And not all browsers support 'unsafe-hashes' for javascript: navigation as for now.
But if I modify my directive to include the hash (example below), I
still get the same error in console (obviously with a different hash).
Why do you stopped? I see you use www.googletagmanager.com (GTM), do you think GTM has only one inline script? You allowed the parent script, it began to load the child ones, so you need hashes for both.
You can use parent script hash + 'strict-dynamic' token to allow all the childs ones, but it does not work in Safari as for now.
At the final you will get a lot of hashes for all inline scripts. Bad thing is that GTM and others can time to time change content of it inline scripts, so you have to add a new hashes and to remove obsoletes. But you don't know which hash to which script belongs.
Therefore the preferable way is to use 'nonce-value' for any inline scripts, all the more since GTM distributes 'nonce' to all inline scripts except Custom HTML Tags. For Custom HTML Tags(if used) you can use hashes, because those scripts is under your control.
It's better to investigate all inline scripts manually before decide how it easier and reliable way to allow them.
PS: GTM is a hard nuts for CSP because GTM can be used to inject a open list of inline/external scripts. And if use the custom JavaScript variable names are used for the «Custom HTML tag», it required to allow 'unsafe-eval'.
You can test your GTM ID for what additional scripts it loads and which CSP is enough for it.
I recently did a CTF challenge where we needed to do an XSS attack on a site with a Content Security Policy ... script-src 'self' ... . This was made possible because the website offered the possibility to upload images, which we used to upload a file containing Javascript code with a GIF header like GIF89a=alert(document.cookie)//;.
All we had to do after successfully uploading that image was call that image with something like http://website.com/<script src=url_to_our_image> and the code was executed despite the CSP.
Now my question: How could you prevent that? I assume you want to keep CSP at ... script-src 'self' ... (you want to trust your own scripts, right?). But what other option would then be left to prevent such an attack? Blacklisting some content of the image, so that it cannot contain code? (I heard that blacklists a generally a bad idea)
We want to secure our site with Content-Security-Policy, and even with the setting of allowing inline scripts (default-src 'self'; script-src 'self' 'unsafe-inline'), loading modernizr (2.6.2) produces 4 CSP violations:
I upgraded to the latest version (3.6.0), the develop version, and now it produces over 30 CSP violations:
I couldn't find any official statement on CSP on the modernizr site, it merely mentions that in 2012, they added a detect for Content Security Policy (https://modernizr.com/news/modernizr-262).
Reading various blogs and Stack Overflow questions, I find most up-to-date best-practice from 2017 to be:
If modernizr is injecting all that inline stuff than it seems like
your choices are to either (a) add all those hashes, (b) use
'unsafe-inline' (but which basically defeats the whole purpose of
CSP…), or (c) don’t use modernizr.
Although, the errors I am getting occur even when using unsafe-inline.
Has anyone found a workable solution to using both Content-Security-Policy and modernizr?
Try using this lenient CSP default-src * 'unsafe-eval' 'unsafe-inline' 'unsafe-dynamic' data: filesystem: about: blob: ws: wss: and start removing keywords until you start getting errors, with this method you can adjust your CSP to your needs.
It would be nice if there was some sort of CSP generator where you give it a website and it just knows which CSP you need in order to not keep erroring.
Remember that * means allow all domains, so replace this with all domains you intent to support.
This of course just fixes, or solves the issue, and it depends what it's at stake, what content does your website offer, and how vulnerable would users be if an XSS attack could be carried through. CSP protects merely against XSS attacks, this is just JavaScript that could be inserted by a third party, using HTTPS for example, will make it almost impossible for a MITM to inject arbitrary code.