In CSP v2 frame-src was deprecated. child-src is recommended to use instead.
In CSP v3 frame-src in undeprecated and child-src is deprecated.
Currently (sep 2017) Chrome:
The 'child-src' directive is deprecated and will be removed in M60, around August 2017. Please use the 'script-src' directive for Workers instead.
So what's correct collection of directives to work in modern (minus 2 versions) browsers? Looks like frame-src + script-src is enough? But what should be in script-src then?
PS: is it even legal to "undeprecate" stuff?
2018-12-20 update
child-src has in the meantime been un-deprecated… So now neither frame-src nor child-src are deprecated any longer. But the guidance from the original answer here still holds true:
So what's correct collection of directives to work in modern (minus 2 versions) browsers?
It seems like the answer to that depends on what exactly you want to specify a policy for.
If your needs are simple and so you don’t want to have different policies for iframe elements and scripts, then just use default-src to specify the same policy for both.
If your needs are more complicated and you want a policy for iframe elements that’s different than the policy for other resources, than use frame-src. Similarly, if you want a policy for scripts that’s different than the policy for other resources, then use script-src.
If you don’t want a policy for worker scripts different than the policy for other scripts, then you’re fine just providing a script-src policy, and can stop there.
If you do want a policy for worker scripts different than the policy for other scripts, then along with providing a script-src policy, provide a worker-src policy too. The worker-src one won’t effect browsers yet, but will future-proof things for when browsers do add support.
See https://github.com/w3c/webappsec-csp/issues/239#issuecomment-336135344 if you’re curious about the rationale for child-src being un-deprecated:
I was hoping other vendors would implement worker-src so we could drive down usage of child-src and remove it from the platform, but it doesn't look like that's happening quickly enough (removing Chrome's weird fallbacks would break a worker load on 0.006% of page views, which is not huge, but not nothing).
2017-09-04 answer
It’s even a bit more complicated than what’s described in the question, because the CSP3 spec also introduces the worker-src directive. But the spec gives the following guidance:
The child-src model has been substantially altered:
The frame-src directive, which was deprecated in CSP Level 2, has been undeprecated, but continues to defer to child-src if not present (which defers to default-src in turn).
A worker-src directive has been added, deferring to script-src if not present (which likewise defers to default-src in turn).
child-src is now deprecated.
That’s in https://w3c.github.io/webappsec-csp/, which is an editor’s draft but is what you should always consult for current spec requirements. Reason: You can’t trust https://www.w3.org/TR/CSP/ to be up to date (and in general you can’t trust anything under https://www.w3.org/TR to be up to date), and editor’s drafts are what browser implementors actually implement from (they don’t wait to implement until something’s published under https://www.w3.org/TR).
Anyway, the reason the child-src directive was deprecated is that its effect is specified as:
The child-src directive governs the creation of nested browsing contexts (e.g. <iframe> and <frame> navigations) and Worker execution contexts.
The problem with that in practice is: an iframe is very different than a worker script. So that’s why worker-src was added and why frame-src was un-deprecated (because you really do want a separate directive to specify policies for iframe elements), and why child-src was deprecated (because you really don’t want to apply one policy to both iframe elements and worker scripts).
So what's correct collection of directives to work in modern (minus 2 versions) browsers?
It seems like the answer to that depends on what exactly you want to specify a policy for.
If your needs are simple and so you don’t want to have different policies for iframe elements and scripts, then just use default-src to specify the same policy for both.
If your needs are more complicated and you want a policy for iframe elements that’s different than the policy for other resources, than use frame-src. Similarly, if you want a policy for scripts that’s different than the policy for other resources, then use script-src.
If you don’t want a policy for worker scripts different than the policy for other scripts, then you’re fine just providing a script-src policy, and can stop there.
If you do want a policy for worker scripts different than the policy for other scripts, then along with providing a script-src policy, provide a worker-src policy too. The worker-src one won’t effect browsers yet, but will future-proof things for when browsers do add support.
PS: is it even legal to "undeprecate" stuff?
Yes. Though I can’t remember ever seeing any other spec or working group do that, it was the right thing to do in this case—because the CSP spec authors and working group realized that child-src was a mistake, and frame-src was actually necessary and it was a mistake to deprecate it.
So they unwound those mistakes—and relatively quickly. And part of why it worked in this case is: frame-src wasn’t deprecated long enough for browsers to ever get around to dropping support for it, and also a lot of web developers never got around to using child-src to begin with.
Related
I am trying to add CSP to our web site, using report-only (to report-uri.com).
It seems to work as expected for most cases, but google related sites gets reported even if the URL is added to the header.
Here´s the relevant part of header as it appears in developer tools:
connect-src 'self' https://stats.g.doubleclick.net
I am still getting this violation:
"blocked-uri": "https://stats.g.doubleclick.net/j/collect"
I have experienced similar issues with other Google related sites as well.
The problem is that we're using Google tags and analysis, so I cannot block the sites out.
This particular problem seems to come from Chrome only.
In addition to blocked-uri, note in the reports on the original-policy field - is there your CSP with the connect-src 'self' https://stats.g.doubleclick.net rule or not.
Looks like some ISPs, in violation of RFCs, cache site responses along with HTTP headers. At least after the changes in the CSP, within 2 weeks there is violation reports having the old CSP in the original-policy field.
And it feels like you changed the rules in connect-src directive recently.
List of sources connect-src 'self' https://stats.g.doubleclick.net is not complete for Google Analytics, you can insert own Google Analytics ID and check. Here is comprehensive test of Content Security Policy for GTM.
Here is initial CSP for GA + GTM. The initial because though GTM you can embed a lot of third-party scripts from vary sources.
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.
When implementing csp-header, I have specified my policy as:
default-src 'self'; script-src www.gstatic.com; Since I have not declared script-src-elem directive in my csp policy, as stated in this mdn documentation, I was expecting policy defined for script-src to be used for script-src-elem directive as well. However, I see violation being reported as "violated-directive":"script-src-elem" "blocked-uri":"https://www.gstatic.com/blah/blah".
Any idea why this behavior is happening?
After seeing this exact same pattern in some of my applications, I finally got to the root of this!
The weirdness we were seeing was that CSP reports were coming in for a hostname which was definitely in the script-src directive; and we know that script-src-elem is supposed to fall back to those directives. From that perspective, it should have been literally impossible for these reports to happen.
Here's what we found: the users these reports were coming from were using the PrivacyBadger browser extension, which was leading to false positive CSP reports for the hosts (Google) that it blocked. I didn't dig too far into it, but here's my theory on how that happens:
The Content Security Policy performs a pre-request check for the JavaScript include on the page (eg. gstatic.com or google-analytics.com). The pre-request check passes, because the hostname is allowed in the policy.
The browser initiates a request for the resource
PrivacyBadger intercepts the request via the browser's onBeforeRequest API (see PrivacyBadger source and Chrome documentation)
ProvacyBadger returns a surrogate data blob for the asset. It does this to ensure that code which relies on the real javascript (eg. window.ga) won't break.
The browser then performs a post-request check against the returned base64 blob
The post-request check fails - because the policy does not allow data: for script-src
The browser sends a CSP report for the blocked asset.
This seems like it might be a browser bug - because the report reflects the original asset's third party hostname; while the blocked content is actually a data: blob that was returned via the intercepted request.
From the documentation you linked to: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src-elem
The HTTP Content-Security-Policy (CSP) script-src-elem directive specifies valid sources for JavaScript elements, but not inline script event handlers like onclick.
Without seeing the rest of your code it is a safe assumption that you are seeing this error as a result of an inline event handler and will need to define script-src-elem in your CSP policy.
script-src-elem definitely does fallback to script-src in browsers on the Chromium engine. Check the Chrome console, the warn will looks like:
... Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
Gecko-browsers does not support script-src-elem and use script-src directly.
The CSP2-browsers in violation reports sends a violatied directive resulting after all fallback chain. But CSP3-browsers send a "theoretically" violated directive and than perform fallback if directive was omitted. This introduces some confusion.
script-src-elem have nothing to do with inline event handler like onClick() -this is noted in MDN docs. script-src-elem controls only <script>...</script> and <script src='...'> elements (and javascript-navigation).
"blocked-uri":"https://www.gstatic.com/blah/blah" says that https://www.gstatic.com host-source was blocked, not inline event handler.
Inline event handlers do lock in the script-src-attr directive and report will looks like "blocked-uri":"inline".
Looks like you edit a copy CSP, but server issues another as default. Please look the "original-policy" filed in the report's JSON. Is it contains you real CSP or some default one?
PS: To detail analyse what's going on it need to look a full violation report and a your full CSP (print screen of browser console messages will be very helpful). Because script-src www.gstatic.com; is totally enough for CSP3-browsers to allow any resources from 'https://www.gstatic.com'. (CSP2-browsers requires more rules but you shown violation report sent by CSP3-browser).
I know I'm late to this, but this thread brought me to the solution for my case:
Disable the NoScript-Addon in Chrome.
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.
I have been having problems with scripts not getting loaded because of problems with content security policy settings and was wondering if there was a way to set a content security policy so that it lets all websites be accessible for downloading scripts?
If you're not sure exactly what Content Security Policy you need, it's fine to start with a policy that's very permissive, (which is at least better than no policy at all) and refine it.
For example,
Content-Security-Policy: default-src 'self'; script-src *
would allow you to include scripts from anywhere, but everything else, for example images, only from your own site.
I would also recommend you start with Content-Security-Policy-Report-Only, which reports errors but doesn't block the content. That way you can safely test and refine your policy before you enforce it.
See for example Scott Helme's blog article
https://scotthelme.co.uk/content-security-policy-an-introduction/