Subject: Re: [httpwg/http-extensions] Cache digest and scoping (#216)

From: HTTP issue updates <[email-masked]>
Date: Thu, 04 Aug 2016 08:31:54 -0700

> When generating CACHE_DIGEST, a client MUST NOT include cached responses whose URLs do not share origins [RFC6454] with the request of the stream that the frame is sent upon.

I'm curious, is there an explanation somewhere why this design was chosen? There seems to be a trade-off between *coverage* (maximizing the amount of useful URLs in the digest) and *privacy* (minimizing the privacy leakages relative to HTTP/2 as it stands currently). As @bryancall points out, the current proposal has suboptimal coverage. To illustrate, here are two alternate strategies:

*Include all URLs for which the server is authoritative*: This is suggested by @bryancall. I believe this strategy maximizes coverage: a server can push any URL for which it is authoritative, and this strategy includes all such URLs in the digest. However, there is an increased chance for privacy leakage. Say a server is authoritative on a.com and b.com, and some user makes requests for a.com. If the cache digest includes URLs from b.com, the server can learn of those URLs even if the client never makes any requests for b.com.

*Tie the digest to cookies*: This idea is inspired by @kazuho's [H2O](https://h2o.examp1e.net/configure/http2_directives.html#http2-casper), which puts the cache digest in cookies. We can't actually store the digest in cookies (it's too inefficient), but if we designed the digest in such a way that it *could* be stored in cookies, at least in theory, then we could argue that cache digests do not increase the chance for privacy leakage relative to current H2. For example, suppose a URL can be included in a cache digest only if the following conditions hold:

* The server is authoritative for that URL.
* The client is making a request for origin https:x.y.foo.com, the URL's origin is X, and the client has a cookie that could be sent with requests for https:x.y.foo.com *and* with requests for X.

I believe this is roughly equivalent to the current proposal if the client does not have any domain-level cookies. However, if the client has a cookie for ".example.com" and the client makes a request for "www.example.com", the cache digest can include URLs from "cdn.example.com". Note that example #3 from @bryancall's initial comment would not work: on a request for "finance.yahoo.com", the digest would not include URLs from "s.yimg.com", although if the server is authoritative for both domains, the client may later make requests for "s.yimg.com", at which point the cache digest could be updated to include URLs on that origin as well.

> CACHE_DIGEST allows such cache-based fingerprinting to become passive, since it allows the server to discover the state of the client's cache without any visible change in server behaviour. As a result, clients MUST mitigate for this threat when the user attempts to remove identifiers (e.g., "clearing cookies").  This could be achieved in a number of ways; for example: by clearing the cache, ...

Expanding on the above design, we could view the cache digest as an internally-maintained cookie. When the browser makes a request to origin X, the browser creates a cookie with the domain set to host(X). If X is https, the cookie is Secure, otherwise it is HttpOnly. From this point forward, each time the browser caches a URL from origin X, it adds that URL to X's cache digest cookie. If a URL is evicted from the cache, it is removed from the cache digest cookie. If a page from origin X sets a cookie on domain(X), then cache cookies for all hosts Y where domain(Y) = domain(X) are linked, as it may be possible to send union(cookie(X),cookie(Y)) when an H2 connection is opened to either host. Note that the cache cookies for X and Y are linked *but not merged* as the external server may not be authoritative for both hosts -- this needs to be checked for each H2 connection.

Except for being created automatically, and being sent in CACHE_DIGEST rather than Cookie, cache digest cookies behave exactly like other cookies. They are cleared when the user asks for cookies to be cleared. They are disabled when the user disables cookies. They are cleared when the browser is closed when the browser was opened in Incognito mode.

There may be concerns about the following case. Suppose all hosts under `.aws.com` are served by the same cloud frontend, which terminates the H2 connection, but each host on this domain is served by a separate backend server. Now suppose `evil.aws.com` sets a cookie for `.aws.com`. Can `evil.aws.com` can spy on a user's from `alice.aws.com`? The answer is yes if the client sends a single cache digest that covers both hosts. I see two ways to prevent this:

1. Although a client may proactively send multiple cache digests, following the above rules, each digest summarizes URLs for a single origin only. (The cloud frontend would be trusted to not forward the digest for `alice.aws.com` to `evil.aws.com` -- this doesn't seem like a problem, since the frontend is already trusted to partition their traffic.) This may use extra bytes by requiring separate-origin digests to be sent in separate CACHE_DIGEST frames.

2. Cache digests from multiple origins can be merged, but the client will merge digests for `evil.aws.com` and `alice.aws.com` only if *both* origins have set a domain cookie for `.aws.com`. This potentially saves bytes by allowing one cache digest to cover the entire connection.

WDYT?

> When generating CACHE_DIGEST ... with the request of the stream that the frame is sent upon.

Relatedly, I'm a bit confused with the last part of that sentence. I would expect CACHE_DIGEST to apply to the entire connection (StreamID = 0x0) rather than an individual stream. Why not send CACHE_DIGESTS on stream 0x0 and include an explicit scope (authority) in the CACHE_DIGEST frame? This costs a few extra bytes but will (a) eliminate a race between receiving the first request and the digest, and (b) make it more obvious *which* authority the digest applies to.

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/httpwg/http-extensions/issues/216#issuecomment-237590179

---

From: HTTP issue updates <[email-masked]>
Date: Sat, 20 Aug 2016 13:53:07 -0700

@mnot 
> Having said that, there's nothing that stops a client from sending multiple cache digests on a connection, one for each origin that the connection is authoritative for. If this needs to be clarified in the draft we can certainly do that.

I think CACHE_DIGEST frame should designate its scope explicitly, considering the fact that drafts that changes the scope of the authority exists (e.g. ORIGIN frame , secondary certificates), and that we have `COMPLETE` flag (that indicates a digest covering all the authorties have been sent).

Otherwise, there'd be a race condition.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/httpwg/http-extensions/issues/216#issuecomment-241223097