Skip to content

Commit

Permalink
Start differentiating the "inner" from "outer" exchanges.
Browse files Browse the repository at this point in the history
  • Loading branch information
jyasskin committed Apr 17, 2018
1 parent ff3bb57 commit 5ecdd35
Showing 1 changed file with 34 additions and 31 deletions.
65 changes: 34 additions & 31 deletions explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ intermediate) and forwards it to a client (or another intermediate).

When an HTTP exchange is encoded into a resource, the resource can be fetched
from a **physical URL** that is different from the **logical URL** of the
encoded exchange.
encoded exchange. We talk about the **inner** exchange, the **outer** resource
it's encoded into, and sometimes the outer exchange that fetches the outer
resource.

## Component documents

Expand Down Expand Up @@ -95,8 +97,8 @@ Signed exchanges can also be sent to a client in three ways:
non-origin signatures and to provide an origin-trusted signature to
intermediates.
1. Enveloped into the `application/signed-exchange` content type. In this case,
the signed exchange has both the logical URL of its embedded request, and the
physical URL of the envelope itself.
the signed exchange has both the logical URL of its inner request, and the
physical URL of the outer envelope itself.
1. In an HTTP/2-Pushed exchange.

### Bundled exchanges
Expand Down Expand Up @@ -246,10 +248,10 @@ reviewed for.

## Signed Exchange Loading Sketch

When an **embedder** prefetches or embeds an enveloped signed exchange, or a
client navigates from the embedder to an enveloped signed exchange, the
client goes through several steps to open the envelope and load the signed
resource.
When an **embedder** prefetches or embeds an application/signed-exchange
resource, or a client navigates from the embedder to an
application/signed-exchange, the client goes through several steps to open the
outer envelope and load the inner exchange.

### Fetch the physical URL

Expand All @@ -260,11 +262,10 @@ embedder's and any parent frame's Content Security Policy, and goes through the
physical URL's Service Worker for navigations or the embedder's otherwise.

Once the response comes back, its `Content-Type: application/signed-exchange`
header tells the client that it represents a signed exchange, but it's initially
treated like any other response: the Response object shown to the Service Worker
(if any) is the bytes of the `application/signed-exchange` resource, not the
response inside it, and the `application/signed-exchange` participates in caches
the same way as any other resource.
header tells the client that it's the outer resource of a signed exchange, but
it's initially treated like any other response: the Response object shown to the
Service Worker (if any) is the bytes of the outer, not the inner response, and
the outer resource participates in caches the same way as any other resource.

### Fetch the certificate chain

Expand All @@ -290,14 +291,13 @@ Each signature with a valid certificate chain is passed on to the next step.

### Signature verification

Once the certificates are validated and enough of the
`application/signed-exchange` resource is received to parse the claimed
signed-exchange headers, the client extracts the logical URL from those headers
and then tries to find a valid signature over the headers that is trusted for
the claimed origin. If none of the signatures are valid, it either
Once the certificates are validated and enough of the outer resource is received
to parse the claimed inner headers, the client extracts the logical URL from
those headers and then tries to find a valid signature over the headers that is
trusted for the logical URL's origin. If none of the signatures are valid, it
either

1. redirects to the logical URL as if the whole signed exchange were a 302
response, or
1. redirects to the logical URL as if the outer response were a 302 redirect, or
2. fails with a network error.

We're not yet certain which behavior is best. The first is slightly more
Expand All @@ -311,7 +311,7 @@ records into a response stream as they arrive.

### Prefetching stops here

At this point, the client's behavior depends on whether the signed exchange was
At this point, the client's behavior depends on whether the outer exchange was
requested as a [prefetch](https://w3c.github.io/resource-hints/#prefetch). To
satisfy the [privacy-preserving prefetch](#privacy-preserving-prefetch) use
case, prefetches can't fully load the logical URL, which would create an HTTP
Expand All @@ -330,34 +330,37 @@ simpler than expected.
### Caching the signed response

If the signed exchange was requested as a navigation or subresource (i.e. *not*
prefetches), the client tries to cache the request→response pair it contains.
prefetches), the client tries to cache the inner exchange.

This *doesn't* happen if:

* The signed exchange's request headers aren't sufficiently similar (TBD) to the
* The inner request headers aren't sufficiently similar (TBD) to the
request headers the client would use for a normal request in the same context.
This prevents a malicious intermediate from sticking the wrong
content-negotiated resource in the HTTP cache.
* There's a response in the HTTP (or any?) cache with a newer Date header
than the signed exchange's response. This prevents some downgrade attacks.
* There's a response in the HTTP (or any?) cache with a newer Date header than
the inner response's Date header. This prevents some downgrade attacks.

In either of these cases, the client just skips to the redirect in the next
step.

If we're still here, the signed exchange is put into a "use-once" cache similar
to the [preload cache](https://github.com/whatwg/fetch/issues/590) and, if the
response headers allow it (and review of this explainer indicates it's a good
idea), the [HTTP cache](https://tools.ietf.org/html/rfc7234).
If we're still here, the inner exchange is treated as if it had been prefetched
from the original origin. Note that the [prefetch
specification](https://w3c.github.io/resource-hints/) doesn't say exactly what
this means. It is similar to the [preload
cache](https://github.com/whatwg/fetch/issues/590) but situated between the HTTP
cache and the Service Worker, and not exactly the same in other respects.

If we put the signed exchange in the HTTP cache, its freshness has to be bounded
by the shorter of the normal HTTP cache lifetime or the signature's expiration.
If this behavior puts the inner exchange in the [HTTP
cache](https://tools.ietf.org/html/rfc7234), its freshness has to be bounded by
the shorter of the normal HTTP cache lifetime or the signature's expiration.
This is more strict than the bound on cache freshness when it crosses a
certificate or OCSP response expiration in order to partially mitigate
[downgrade
attacks](https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#seccons-downgrades).
For *later* loads of the logical URL (in particular, not the load that's
happening through the signed exchange, since it's fulfilled using the
above-mentioned "use-once" cache), a stale entry can be revalidated in the
above-mentioned prefetch cache), a stale entry can be revalidated in the
following ways:

* If the `Signature` is expired but the HTTP caching information is fresh, the
Expand Down

0 comments on commit 5ecdd35

Please sign in to comment.