Skip to content

Device-Bound Session Credentials Analysis #1094

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Conversation

martinthomson
Copy link
Contributor

This is my analysis of DBSC, which suggests a different approach to the design that is more congruent with the way that cookies operate today and uses existing technology.

I propose that this be the substance of the TAG's response to #1052, and that we close that issue (for now) with an "unsatisfied" resolution.

This is my analysis of DBSC, which suggests a different approach to the
design that is more congruent with the way that cookies operate today
and uses existing technology.

I propose that this be the substance of the TAG's response to #1052,
and that we close that issue (for now) with an "unsatisfied" resolution.

Note that the server does not need to refresh the signed cookie. That cookie could be a stub that only exists to elicit a signature, so it could have a very long lifetime.

These multi-step arrangements would result in similar amounts of delay as the process in the proposal. This approach is still better, because it follows fairly ordinary cookie handling for the most part. Any additional steps would be discretionary on the part of servers, which could sometimes choose to accept either the extra requests with signatures[^2] or the heightened risk of TPM compromise. Alternatively, servers could streamline the overall process by combining steps, at the cost of additional coordination between the different resources. In comparison, the proposed design makes an extra step unavoidable, so making this discretionary is strictly better.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If our alternative doesn't improve the number of requests, we shouldn't flag the 2 round trips as the biggest problem with the current design. We should instead say something like "we think there's a way to re-use existing cookie patterns" or, "we think there's a way to allow the server to save some round trips if it doesn't need all the security provided by the original proposal".

In fact, I think this alternative produces 3 extra round trips (/some/resource, /login, /login/1EU9jsh07pci6Cgk9Bh0, /some/resource), while the original only added 2 as long as the client has a good-enough clock to anticipate that its cookie will be expired (saving the original guaranteed-to-fail request to /some/resource).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the focus on delays is wrong, I'll look at it closer.


This is a sketch of an alternative approach that is far closer to how the web platform currently handles cookies.

The core requirement for the usage part is that the site is able to regularly request that the browser demonstrate that it has access to the private key that was registered through the enrollment process. Ideally, that access is not required for most interactions, because generating and validating a digital signature is somewhat expensive for both client and server.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This contradicts footnote [^2], which claims the client-side cost is trivial. We should be internally consistent.


```http
303 Over Yonder
Location: /login
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should include the ?prev=/some/resource query parameter that's needed to redirect back to the source page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server knows that. It's just that servers often ask clients to hold stuff while they are busy. I thought it would be distracting, but now I see that the opposite is true. I'll fix it up.

This resource then makes a call about the freshness of the login cookies and determines that a signature is needed. It initiates another redirect, including fresh entropy in the URL to guarantee that the client has live TPM access.

```http
303 Over There Now
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom reason-phrases are distracting me, and making me wonder if they have a semantic meaning. They don't, but we should avoid distractions for other readers.


Any `Set-Cookie` header that establishes a `Signed` cookie could list the key types in the `Signed` attribute, but the `Accept-Signature` field exists for negotiating the use of signature keys. The server should therefore use `Accept-Signature`.

The `Cookie` header that the browser subsequently sends will be signed. That same message can include the public key from the key pair. That’s usually not something that can be included in the signature as defined in the current RFC. For that, we might define a new `Signature-Public-Key` field to carry the necessary information. We could define a new `Signature` field parameter, but that could be confused with `keyid`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm worried about us saying that "here's an alternative design, but you're still going to need to figure out how to modify the message-signature RFC". If that's not straightforward, they're just going to say their current design is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not at all what this is saying, it's saying that there is a need to define a way to communicate a public key and that is something the message signature RFC doesn't solve.

martinthomson and others added 2 commits May 19, 2025 10:38
Apologies to those who reviewed in the past.  Adding wrapping is the
right thing to do, but it blows away all the comments.

I've tried to address the feedback about clarity, so there are parts of
this that are rewritten.  In particular, there is a new section on
hiding latency that doesn't claim superior latency in the proposed
alternative.  Instead, it focuses on certainty for servers.

New text talks about the obvious reduction in latency that can be
achieved.  Then it talks about the non-obvious ways in which the
original proposal was able to hide latency and how the alternative can
use the same tricks, but in a more flexible way.
@martinthomson
Copy link
Contributor Author

Relaying commit comments from c0527a0 here:

Apologies to those who reviewed in the past. Adding wrapping is the right thing to do, but it blows away all the comments.

I've tried to address the feedback about clarity, so there are parts of this that are rewritten. In particular, there is a new section on hiding latency that doesn't claim superior latency in the proposed alternative. Instead, it focuses on certainty for servers.

New text talks about the obvious reduction in latency that can be achieved. Then it talks about the non-obvious ways in which the original proposal was able to hide latency and how the alternative can use the same tricks, but in a more flexible way.

There are a few other modest changes in there as well.

Copy link
Contributor

@jyasskin jyasskin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial thoughts, but I won't get through the whole change before the meeting.

Comment on lines +78 to +85
We have an alternative below that doesn't require an interactive exchange.
However, given that TPMs generally don't have a clock,
you can't use the clock to ensure freshness.
A non-interactive exchange might have been pre-generated by an attacker
who temporarily had access to the TPM, unless it contains fresh entropy from the server.
That's something we address in more detail in the alternative design below,
noting that the alternative offers servers more options to combine requests to reduce latency,
where the proposal cannot.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth spending time on this? It'd be possible to tweak the proposal to avoid the interactive exchange too, with just a flag in the enrollment that causes it to use a constant challenge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an important point in the requirement space to acknowledge. That is, part of the point of the feature (perhaps the entire point) is to enable this sort of liveness test. As the explainer isn't very clear about this aspect of the design, I thought it worth repeating.

This would not guarantee that sites would ask for passwords less often, but it would be good if it had that effect.

There are two major parts to the design of this feature: enrollment and usage.
This document will first look at usage, because that is the part that could be simplest.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting confused by seeing usage come before enrollment, since chronologically enrollment happens first and establishes that conditions that make usage possible. Can you swap them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deliberately put usage first, because that is the important one and it is the easiest to reason about.

Comment on lines +128 to +131
Overall, this creates a new set of interaction paradigms between the browser and websites.
We think that there are easier ways to achieve the same basic goals
without too much disruption to the existing cookie handling arrangements.
That design is sketched below.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use of the DBSC proposal seems fairly simple, while the alternative looks more complex to me, even if it might trust client-side clocks too much. We should acknowledge that here.

I think the key benefit of our alternative is that it adds a simpler primitive to the platform, and even though use is more complex, that single new primitive can combine in very interesting ways with the rest of the platform.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that you are underestimating the complexity of a model in which you have to stand up a special service just to manage these cookies. Obviously, a large part of that complexity burden is borne by the browser implementers, but trying to extract the right behavior from that model is likely to lead to equivalent complexity, if not more, than the alternative. Don't be mislead by the completeness of the example: all that complexity is present in the original proposal, plus more.

Comment on lines +151 to +153
That design might include a new `Signed` parameter for cookies in `Set-Cookie`.
That attribute would request that, whenever the cookie is sent to the server,
the client would cover that cookie with a signature.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks to me like signed cookies need enough extra handling that they might deserve a new Set-Signed-Cookie header instead of just a Signed parameter. In particular, for creation, it's important that the client immediately make a request with the new public key, so the header ought to identify a URL that should be the target of that request.

Then ... in what ways is Set-Signed-Cookie different from Secure-Session-Registration? One way is that it doesn't intrinsically have support for https://w3c.github.io/webappsec-dbsc/#federated-sessions. We haven't analyzed the federated sessions in this document. They're a bit like a proposal Johann made to grant storage access if one site could prove that it knows a secret that's only available to another site...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I didn't look too closely at the federation text there. The potential that things might be linked without going through the accepted processes (FedCM primarily, though also Storage Access on its own) concerned me enough to discount this.

Again, this is a case where the signing of the cookie allows for self-service. Under any regime where you can obtain unpartitioned cookie access, this is pretty trivial. The embedded SP (or IdP) gets the signatures it would have normally. It can then tell the top-level site that everything is good. At which point the top-level site can either set an ordinary cookie or it can do its own binding to a key in the TPM, remembering how it was blessed.

BTW, that whole idea about guessing secrets is a fine one, but orthogonal to this. This is about ensuring that cookies cannot be stolen. It is also probably an idea that makes cookie theft even more consequential, as it creates a way to stealthily track if you can guess correctly.

Comment on lines +162 to +164
It is not likely to be sufficient to just cover `Cookie` in the list of signed content in `Signature-Input`.
Including a date (the `created` parameter), the method (`@method`), and the URL (`@target-uri`)
seem to be the minimum set of things that will prevent the signature from being reused.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's another use for a dedicated Set-Signed-Cookie header: it could list the component identifiers that need to be signed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't argue either way for something like that. Either something needs to be signed to achieve some goal, or not. How something is spelled has no effect on that.

The only reasons I can see that would justify a distinct header are:

  • to ensure that you don't get a signed cookie back from a client that doesn't understand the new feature
  • to avoid all that __Secure-/Secure, HttpOnly, etc baggage that cookies have accrued over time

The first is pretty trivial to handle gracefully. The second has a long history of failure.

seem to be the minimum set of things that will prevent the signature from being reused.
It's possible that a more thorough security analysis will identifier other fields that need to be covered.

## Some Challenges
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section should be about how to accomplish various use cases, and I think it should start with a demo of how to satisfy the single threat model that DBSC currently covers: you trust the client's clock but not their timestamps. Then we can follow up with the extra flexibility that re-using cookies allows.

Suggested change
## Some Challenges
## Implementing various use cases
### Interactive proof if the client knows when to refresh

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

Successfully merging this pull request may close these issues.

3 participants