Skip to content
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

Planning server-side agility #40

Open
punkeel opened this issue Jan 1, 2025 · 5 comments
Open

Planning server-side agility #40

punkeel opened this issue Jan 1, 2025 · 5 comments

Comments

@punkeel
Copy link

punkeel commented Jan 1, 2025

Related to #37 but different enough to warrant its own issue, imho.

Clients can request certain properties in the signature using the Accept-Signature header. The present RFC currently gives the following example: Accept-Signature: sig0=("identity-digest";sf);keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";type="sri".

My concern is that changes to that header are potentially breaking changes, depending on how user agents enforce them.

Quote from RFC-9421:

By this process, a signature applied to a target message MUST have the same label, MUST include the same set of covered components, MUST process all requested parameters, and MAY have additional parameters.

The receiver of an Accept-Signature field MAY ignore any signature request that does not fit application parameters.

The present RFC suggests:

  1. [snip]

  2. We could require additional components of the request to be included in the signature ("content-type", "@path;req", "@method;req", etc) in order to reduce the scope of potential resource substitution.

  3. We could allow developers to send a challenge along with the request (as an [Accept-Signature](https://www.rfc-editor.org/rfc/rfc9421.html#name-the-accept-signature-field) parameter), and require that it be incorporated into the [Signature-Input](https://www.rfc-editor.org/rfc/rfc9421.html#name-the-signature-input-field)'s "nonce" parameter.

[3.] makes offline signing difficult

These sort of changes would be breaking changes, directly impact how developers implement signatures, and change the threat model we help protect against:

  • is offline signing an option?
  • does the web-server need access to the signing key?
  • can the resource be hosted on a different hostname? CDN?

Separately from this decision, maybe it would make sense to help developers (SWAG?) pick a list of sensible components/parameters to include, if possible? For example, I believe I should always include @authority in my signature to play nicer with CSP, but I'm not sure I'd want it enforced everywhere.

@mikewest
Copy link
Member

mikewest commented Jan 7, 2025

My concern is that changes to that header are potentially breaking changes, depending on how user agents enforce them.

Right now, we treat Accept-Signature as a minimum bar. The header informs servers about the client's keying expectations, and we'll require a match between the keyid parameters (albeit indirectly through enforcement of integrity constraints). However, there's no constraint on either additional parameters or additional components. I'm leaning heavily here on the "MAY ignore any signature request" language in the RFC to justify this, and should probably add some explanatory text.

If we added things like nonces, I'd expect us to include those in the Accept-Signature header as well, and to likewise require a match in that parameter (see #41). If we began requiring additional components, I'd expect those to be in the header as well.

As you note, this would be a change that required developers to come along with us. We'd approach it like any other breaking change. That said, it's not clear to me that we'd want to enforce these kinds of requirements at a platform level. I'd instead aim for allowing applications to define constraints that make sense for their use cases, and giving them hooks that allow clients to understand what they should enforce. #41 describes how we might do this for nonces. It'd be feasible to extend that to components as well (though it'd end up being fairly verbose, and we might want a page level construct, a la require-sri-for or <meta name="sri-ed25519-constraints" content="nonce=xxx, components=a,b,c"> or etc).

is offline signing an option?

I think it ought to be, as it's the only model that keeps signing keys off of frontend servers.

does the web-server need access to the signing key?

Ideally, no! But in dynamic implementations, probably. @ddworken can probably expound upon Google Security's initial thoughts on this; my understanding is that both offline and online scenarios exist, and they'll mitigate risk by having different keys for different resources.

can the resource be hosted on a different hostname? CDN?

I don't see why not. Including @authority might make sense for some scenarios, but it seems like it would complicate rollouts (e.g. prod.amazing.app vs staging.amazing.app) and constrain delivery options unnecessarily. The entire idea here is to remove the necessity to trust that any given server is delivering approved content by shifting trust to the signer. As long as the resource is validly signed, why does it matter where you got it?

So, I agree that I wouldn't want it enforced everywhere. :)

Separately from this decision, maybe it would make sense to help developers (SWAG?) pick a list of sensible components/parameters to include, if possible?

I think there are two levels here:

  1. We need to define the set of supported components (or say that we support everything) along with serialization rules (which in the latter case would be somewhat complicated as we'd need to define all the structured field types as per 1.4 of RFC9421). I'd like to be as flexible as possible, but I'd also like the system to remain predictable for developers.

  2. We should give developers recommendations about the circumstances in which a given set of components/parameters would be helpful (probably conceptually similar to https://w3c.github.io/webappsec-post-spectre-webdev/).

SWAG could help with both, I'm confident. /cc @simoneonofri @torgo

@punkeel
Copy link
Author

punkeel commented Jan 7, 2025

I'd instead aim for allowing applications to define constraints that make sense for their use cases, and giving them hooks that allow clients to understand what they should enforce.

Fully agree. I hadn't even considered this way of enabling them. 👍 Apologies for the dumb take because of that :)

[snip... @authority...] The entire idea here is to remove the necessity to trust that any given server is delivering approved content by shifting trust to the signer. As long as the resource is validly signed, why does it matter where you got it?

Hm, yeah, that makes sense. I was approaching it from the angle that we can't revoke signatures, enforcing @authority lets "me" control what resources are ever served.

Between the <script src=...> tag in the page and the public key in that same tag; I'm not sure @authority makes much sense.

We need to define the set of supported components

Re-reading the RFC, I now realize components[0] [is](https://infra.spec.whatwg.org/#string-is) the string "identity-digest". is the only allowed component.

@mikewest
Copy link
Member

mikewest commented Jan 7, 2025

We need to define the set of supported components

Re-reading the RFC, I now realize components[0] [is](https://infra.spec.whatwg.org/#string-is) the string "identity-digest". is the only allowed component.

Yup. But that's clearly not what we want to ship, so I'd suggest considering it a bug. At the very least, we want to include derived components like @path (and @authority too, along with most of the rest, because why not? I'm sure there's a use case for someone (as you mentioned above) and they're ~trivial to support.).

Header components are more complex only because of serialization. But we should be able to define a reasonable subset to start with, and expand it over time as people point out things we missed.

@yoavweiss
Copy link
Collaborator

SWAG could help with both

What's SWAG? :)

It'd be feasible to extend that to components as well (though it'd end up being fairly verbose, and we might want a page level construct, a la require-sri-for or <meta name="sri-ed25519-constraints" content="nonce=xxx, components=a,b,c"> or etc).

Makes sense and would address my comment on #5 (comment)

@mikewest
Copy link
Member

mikewest commented Jan 8, 2025

SWAG => https://www.w3.org/community/swag/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants