-
Notifications
You must be signed in to change notification settings - Fork 7
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
Inline scripts, CSP, and SRI #10
Comments
I'd continue punting on this for the moment. Let's work out how we do things in HTTP, and then determine how to apply that to HTML. Guessing wildly, if we end up running with the model in #16, we'd add some attributes to a script block that allowed the expression of a signature over that block, and keep the key in the |
I agree with the "later" sentiment. It'd be great to see actual deployment use cases before investing efforts in this direction. |
I have an actual deployment use case which basically requires this, which I believe to be very common in industry: I am creating a page (or in some cases a portion of a page) with a dynamically generated inline script, and the CSP is added to that page downstream from me - significantly downstream from me, often by a different company entirely and not just a different part of my org. The script really needs to be inline for performance and operational reasons, so I can't use a host source. The script is dynamic so I can't use a hash. There is no way easy way to have out-of-band communication between me and the thing which is adding the CSP, so I can't use a nonce. That means I am forced to tell the people maintaining the downstream server that they must add If I could use a public key for inline elements instead, all would be well: when generating the page I'd sign the script's contents and add Please don't neglect this use case. |
Thanks for the use case, @bakkot! I still see this as an enhancement that isn't necessary for getting something out the door, but I do think we have a reasonably stable HTTP side of things at the moment that should make it possible to sketch this in more detail. I think it boils down to two things:
WDYT? |
I agree it's not strictly necessary for getting something out the door, though given how often things seem to get partially done and then never fully updated to address other identified use cases I'd really like to push for including this in the initial spec rather than punting to the indefinite future and continuing to tell people they have to use
Well, yes if we're overloading that attribute, though that's less of an issue if using a different attribute, in which case it would only need to be updated to check signatures and not hashes.
Either of those seem fine. Though the simplest thing would be to just stuff the key into the Also, CSP will need to be updated as well so that it knows to allow inline scripts whose integrity declares a key which is present in the hash-sources list. It's unfortunate that there's currently this split responsibility for checking hashes, where SRI does external ones and CSP does inline ones, and this would further complicate things in that SRI will be responsible for checking signatures for both external and internal scripts. But that's just complexity on the spec side, not something which affects developers. |
I should mention that there's use cases for a |
The bulk of the interest I've seen thus far has been from folks operating servers which deliver script into someone else's page via If folks are willing to spend time on it, I certainly don't object to getting it done now as opposed to later. To that end, it'd be helpful to have a broader set of folks who want inline signature checks to make sure that we understand the use cases and can satisfy their requirements, and to help browser vendors understand the relative priority of this work vs everything else on their plates.
Yup. I think the work (both in specs and implementations) would be the ~same in either case, since validating the signature requires generating a content digest.
Right. You could imagine a few ways of spelling this. That said, another question this raises is how well the HTTP Message Signature framework that the HTTP side of this proposal depends upon applies to inline content. In particular, what are we actually signing for inline scripts? I think we have two broad options:
Yup. This needs to happen in any event (#36).
I understand the use case, and it's not unreasonable. We'd need to specify not only the signature but also the metadata over which the signature is generated (basically replicating the The content digest needs to be part of that base in order to tie it unambiguously to the response it purports to validate. If you need to provide the digest along with the input and signature, it seems like you're losing the deployment advantage of signatures. |
I can try to get other people to chime in, though the sort of people who run into this kind of thing do not tend to be the sort of people who are working on web specs. That said, you can do some of this research for yourself: pick a random retailer - Apple, Walmart, CVS, Aldi, whatever - and view-source, and you will almost certainly find inline scripts. And if they have a CSP at all, they are almost certainly using
I haven't actually read RFC 9421, but the readme has this: That implied to me that for HTTP the expectation is that we're signing exactly the content of the script, at least in the default case. So I was assuming we'd be doing the same here. Is that not so?
Say more about this? Isn't the digest just a function of the contents? Why would you need to provide it? Also, Ed25519 already computes a digest as part of its operation. |
Useful feedback, thanks. It would be helpful to understand more about the ways in which these externally-controlled inline scripts are included, which I imagine varies from folks copy/pasting the scripts into their CRM on the one end, through to server-side includes or more complicated distribution methods on the other. The latter would seem conducive to passing nonces, while the former certainly requires stasis. Both approaches do require some level of coordination between the CSP header (even if delivered as a
That is indeed an oversimplification: https://wicg.github.io/signature-based-sri/#basic-example and https://wicg.github.io/signature-based-sri/#examples tell a more fulsome story. TL;DR: We sign something we can verify as soon as we have the HTTP Message Signature headers, which RFC9421 refers to as a "signature base". That contains the digest of the content, which we then independently verify against the content once it finishes streaming in. That is, the signature is over something like:
Not:
I guess you're right that we could synthesize the digest along with the rest of the signature base. That has some substantial implications for the implementation (I'd need to move all Chromium's validation to the renderer and out of the network stack, which has implications I haven't thought through), but it's certainly possible. |
Something like server-side includes is the common case, yeah. But I don't know why you think that's conducive to passing nonces. The (often several) servers (or build systems) which are adding in the scripts are usually well upstream of, and in some cases completely oblivious to, the servers which are adding in the headers, and have no particular way to communicate with them to coordinate on a nonce. Here you should imagine the CSP header being inserted by something like BIG-IP's Request Header Insert or Cloudflare's HTTP response header modification rules. These rules are managed by humans and can be manually updated for rare events like key rotation, but you wouldn't want a human to have to manually update them every time one of the scripts on the page changed its contents (especially when the scripts are dynamically generated). Furthermore, the HTML is generally cached after being generated (but before adding the headers), and rewriting it on every request to add nonces would be prohibitively expensive even if it were technically feasible to coordinate with the downstream server which is adding the CSP header. Note, also, that I'm not just talking about externally-controlled scripts. That's the case I personally have to deal with, but it is at least as common that the script is produced internally but by a completely different team (and server) than the team (and server) which is managing the CSP header, such that coordinating across those servers would require redoing the entire network stack.
Ah. Alas. That's a lot of machinery which doesn't seem very necessary here. I'd advocate for the thing signed for inline signatures to just be the contents of the script, rather than trying to pull in the rest of the complicated machinery. |
Thinking further, a key plus a signature over the contents is actually a lot more like the existing hashes in the So a concrete proposal, pulling in this issue plus #42:
The values in CSP would still just look like |
Nonces could be passed in along with the request for the script. This assumes more capacity for dynamic content than you suggest is available, though, which is unfortunate.
That sounds complex indeed.
That's a reasonable thing to advocate for. I think it creates some confusion when an inline script has an entirely different signature than one loaded over HTTP, but perhaps that's the right tradeoff (as we'll discuss below).
I appreciate the insight here that it might be reasonable to treat inline content as distinct from content requested from the network. Let me push that a bit further, as I think there's value in creating some mechanism that allows developers to make provable assertions about content inlined directly, but I don't think the constraints there are actually similar to the draft spec we're discussing, and separating them clearly makes it easier to explain why the signed content is different in each case. So, rather than trying to jam them both into the same underlying infrastructure, let's consider the one thing to be relevant to subresources loaded from elsewhere, and the other thing to be relevant to an element's content. My version of this distinction basically inverts yours. :) I'd suggest that we continue treating For a page's content (including but not limited to scripts), I don't think there's ~any value in embedding digests, but signatures seem more reasonable to support. Rather than relying on HTTP Message Signatures for a page's inline content, we could allow developers to assert a set of trusted keys for a given document (e.g. through an (As an aside, this discussion vaguely reminds me of @arturjanc's proposal to extend hashes to cover URLs declared through |
(@annevk might know if anyone has suggested this kind of validation for HTML content in the past (and might have opinions about it, in any of its variously possible spellings)) |
Let's see:
|
I guess we'd do the same thing here that we do for CSP (which consumes the element's child text content via step 19 of prepare the script element.
That proposal seems more direct than this one, insofar as the content is referenced by its exact base64 encoding rather than a proxy (digest or signature), but I see the similarity.
Possibly? If we wanted to extend the concept, we could squint and call this a content nonce (e.g. a number used once for a given paring of content and key?), and just assign special meaning to a nonce that began with a given signature algorithm prefix (e.g.
I'm not entirely sure about the value of extending this to arbitrary elements: scripts and stylesheets will likely remain the most meaningful content to protect, and if it's expensive to do the same for other elements, it seems fine to exclude them. That said, if you really are embedding arbitrary content from a partner, it would be ideal to ensure that certain important content renders only if it's signed by that partner. Terms of service for a sweepstakes that some startup is running on your behalf? 🤷 Interesting thought experiment in any event. |
|
In an effort to avoid some more important work (and the news), I sketched something out in https://mikewest.github.io/inline-integrity/ that only focuses on |
If CSP whitelists a hash, an inline script with that hash or a remote script with that hash in its integrity attributes are both signed. If a CSP whitelists a public key, can we figure out a way to get it to work with inline scripts? Can we reuse the integrity attribute somehow? Or do we need a new attribute?
The text was updated successfully, but these errors were encountered: