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

Integrate b1 signed exchanges with Fetch #281

Merged
merged 9 commits into from
Aug 20, 2018
Merged

Conversation

jyasskin
Copy link
Member

@jyasskin jyasskin commented Aug 6, 2018

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
Copy link
Member Author

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?

Copy link
Collaborator

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.

Copy link
Member Author

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
Copy link
Member Author

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?

Copy link

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.

Copy link
Member Author

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.

Copy link

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?

Copy link
Member Author

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
Copy link
Member Author

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?

Copy link
Collaborator

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
Copy link
Member Author

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`,
Copy link
Member Author

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?

Copy link

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?)

Copy link
Member Author

@jyasskin jyasskin Aug 7, 2018

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.

Copy link

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.

Copy link
Member Author

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}
Copy link
Member Author

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
Copy link
Member Author

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
Copy link
Collaborator

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?

Copy link
Member Author

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.

Copy link
Collaborator

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
Copy link
Member Author

Choose a reason for hiding this comment

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

@davidben @sleevi How many hives does this bit give you?

Copy link

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 :/

Copy link
Member Author

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.

@jyasskin jyasskin force-pushed the loading-spec branch 2 times, most recently from 00207d0 to cf4eb32 Compare August 8, 2018 18:36
@jyasskin
Copy link
Member Author

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.

@nyaxt
Copy link
Collaborator

nyaxt commented Aug 20, 2018

Given that other @jyasskin PRs build on top of this PR, I'd like to proceed with this and then revise the bits later. @kinu Are you cool with this?

@kinu
Copy link
Collaborator

kinu commented Aug 20, 2018

Okay, let's merge it and consider separate PRs if we find any modifications are needed.

@nyaxt nyaxt merged commit 51fa4e8 into WICG:master Aug 20, 2018
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
Copy link

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.

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.

None yet

5 participants