-
Notifications
You must be signed in to change notification settings - Fork 114
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
Integrate b1 signed exchanges with Fetch #281
Conversation
loading.bs
Outdated
the stashed response. | ||
|
||
A Service Worker for `https://distributor.example.org/` gets to handle the | ||
original request. A Service Worker for `https://publisher.example.org/` does not |
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.
@kinu Have y'all looked into the Service Worker side? I believe Fetch's https://fetch.spec.whatwg.org/#concept-http-fetch step 4.2
If request’s redirect mode is "follow", then set request’s service-workers mode to "none".
prevents all redirects from hitting a service worker, so even if distributor.example.org just served a 302 to publisher.example.org, publisher.example.org's SW wouldn't get to handle the navigation. Am I misreading anything?
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.
For navigation the default redirect mode is "manual", therefore every time a request's redirected corresponding SW has a chance to see it.
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.
Aha! Thanks!
I think both @cramforce's idea to use the preloadResponse
and asking people to call fetch()
with cache=="only-if-cached" will work, but to use "only-if-cached" we'll have to tell people to modify the original request or its clone, instead of creating a new request with the same URL. A new request with the same URL won't have the stashed exchange attached, and wiring those up will require an extra global map in the SW itself, which could also get confused by interleaved requests to different signed exchanges holding the same publication URL.
exchange trusted for longer, are constrained to modify the client's clock | ||
and can't also attack its estimate of its skew. | ||
1. Let |message| be the [=b1 signed message=] for |signature| and |headerBytes|. | ||
1. Let |publicKey| be the [=certificate/public key=] of |parsedSignature|'s |
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.
@sleevi @davidben The fact that the certificate is stored un-parsed means that the spec winds up saying to parse out a public key twice, which feels like a security risk. How much can systems actually parse these structures ahead of time, vs when they're validating origin-trust?
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.
Can you explain why it feels like a security risk? I'm not sure I fully understand the question. Extracting an SPKI from a certificate is something easy on virtually all systems - the question is whether or not it's "trusted" data 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.
I've been conditioned that any time we parse something twice, security bugs appear in the differences between the two parsers. However, if you're comfortable with this case (e.g. that nobody will actually write separate parsers), I'm also happy with it.
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.
I presume they're going to be using the same parser - is there reason to believe they may be different?
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.
No particular reason.
|
||
In <a spec="fetch">HTTP-network-or-cache fetch</a>, after | ||
|
||
> 5.19. If |httpRequest|’s [=request/cache mode=] is neither "`no-store`" nor |
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.
Right now, I'm ignoring all of the cache modes in deciding to accept a signed exchange's content. They may be useful in controlling how to fetch the .sxg
itself, and applying them to the content would probably just have the effect of forcing that to the network, which would defeat the point.
Does that sound right to y'all, or do you see any of the modes I should apply 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.
This sg to me.
[=stateful request header=] or |exchange|'s [=exchange/response=]'s | ||
[=response/header list=] includes a [=stateful response header=], return | ||
"untrusted". | ||
1. If |signature|'s [=exchange signature/expiration time=] is more than 604800 |
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.
I check the length of the validity window in cross-origin trust rather than while parsing the signature so that other uses of signatures can define their own maximum validities. e.g. maybe the Play store wants to sign that it's audited an app and have that be valid for more than a week.
loading.bs
Outdated
Note: This does not check for revocation of intermediate certificates, and | ||
clients SHOULD implement another mechanism for that. | ||
|
||
1. If |leaf| doesn't have enough SCTs from trusted logs return `untrusted`, |
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.
@sleevi Is this a reasonable way to phrase the requirement?
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.
No. There's no such thing as "trusted logs", and this also isn't how clients evaluate whether a certificate complies with a given CT policy.
I think much of this algorithm can be replaced by waving into the blackbox and saying that the OCSP response, the SCTs, and the certificates are inputs, for the host, and determine the response. I suspect you may want an added requirement on the OCSP responses freshness, or that the validating client MUST support Certificate Transparency (or is it optional for UAs that don't support CT but still support SXG?)
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.
So put this all in the "Attempt to build a trustworthy path" step? Sounds good; how's this new wording?
I don't think CT should be optional for signed exchanges even for UAs that don't use it for TLS connections. Knowing that a certificate was mis-issued has been an important part of our security analysis.
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.
You realize this means that only Chrome will implement SXGs for the foreseeable future? Coupling to CT in this way is going to either explicitly preclude certain UAs, or encourage them to adopt patterns that they've been reticent to do for TLS, precisely because they know it will harm the CT ecosystem. We should sync up on that. I realize the intersection between CT relates to SXG, but I think we need to be careful about MUSTing certain policy bits, compared to highlighting the tradeoffs.
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.
This is now a SHOULD with a link to a new Security Considerations section.
1. Return "match". | ||
|
||
|
||
## Stream algorithms ## {#stream-algs} |
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.
@domenic This whole section could migrate to either Fetch or Streams if you think it'll be useful to other specs.
for [[draft-yasskin-http-origin-signed-responses]] will use distinct context | ||
strings. | ||
1. A single 0x00 byte which serves as a separator. | ||
1. The concatenation of the following [=byte sequences=], which is the |
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.
@davidben How do you feel about this message algorithm? I think we can simplify it for b2, since I only made it this complicated to avoid confusion between multiple versions of the message, and that's now handled by the HTTP Exchange 1 b1
context string, but it'll inform whether we can go to Origin Trial with b1 or have to go to b2 first.
request. The redirect applies all the usual processing, and then when it would | ||
normally check for an HTTP cache hit, it also checks whether the stashed request | ||
matches the redirected request and which of the stashed exchange or HTTP cache | ||
contents is newer. If the stashed exchange matches and is newer, the UA returns |
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.
This means that whenever UA loads things from a Signed Exchange UA also needs to check HTTP cache. Can you clarify what situation we are trying to deal with by this? If we don't cache the stashed exchange it feels it's just fine, or a site should probably set a short expiration date?
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.
Imagine that Vashti visits https://app.com/ regularly, and app.com also publishes a signed exchange valid for a week to allow offline distribution. Now app.com discovers a vulnerability and patches it, but the vulnerable signed exchange is still out there.
If Vashti visits the site after the update and gets the new version into her cache, even stale, then even if an attacker manages to serve her the vulnerable signed exchange, she won't use it.
This isn't an absolute defense against anything, but it lowers the probability of a successful attack on frequent users of a site.
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.
Chrome's current impl is not following this, which is the biggest concern, but that part probably needs a separate discussion anyways to proceed. (I'll file an impl bug and take a closer look if this needs to block our further milestones)
1. Let |clockSkew| be the uncertainty in the UA's estimate of the current time | ||
caused by clock skew on the client. The UA MAY set this to 0 or use a more | ||
sophisticated estimate. | ||
1. If the UA's estimate of the current time is more than |clockSkew| before |
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.
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.
I'm not going to have bandwidth to review this this week, in part because I need to go get treated for hives. It quite concerns me, and I can tell it's going to take time and focus that I don't yet have to adequately review :/
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.
SG. I've added a pointer to #141 so that anyone implementing this knows to check with security folks.
00207d0
to
cf4eb32
Compare
This still needs a definition of request matching in a subsequent PR, and it probably has several mistakes, which I'm hoping my reviewers will catch.
As previously agreed with Chrome's loading team.
Hooking into HTTP fetch gives me an easy way to inject a redirect, but it means that signed exchanges loaded from the filesystem, from blobs, etc. don't work. In the long run, I think we'll want them to work, so we'll want to either move the attachment point up to main fetch, or manually go through some of the redirect steps in the other branches of scheme fetch. I still think this PR is the right place to start: it'll be easier to see what that extension changes with this as a baseline. |
Okay, let's merge it and consider separate PRs if we find any modifications are needed. |
1. If |browserRequest|'s [=request/url=] is not [=url/equal=] to | ||
|storedRequest|'s [=request/url=], return "mismatch". | ||
|
||
1. Issue: Flesh this out, along the lines of |
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.
Note that the way this is rendered in Safari looks a bit weird, I only see step 1. and 3. with a big ISSUE section in between. But I guess once Step 2 has been fleshed out, it will look ok.
Preview