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

Double-keyed HTTP cache #904

Open
annevk opened this issue May 9, 2019 · 25 comments

Comments

@annevk
Copy link
Member

commented May 9, 2019

The idea here is that the "browser's address bar origin" is an additional key for its HTTP cache, to prevent certain classes of attacks.

Safari ships a variant of this (uses registrable domain, not origin), but seems willing to adjust to origin. Other implementers are interested in shipping and are at various stages of experimentation.

This will require making all accesses of "the HTTP cache" more contextual, by accessing the HTTP cache of X whereby X is some defined origin. (Other ideas welcome, @mnot?)

I'm not sure where to store the defined origin. We could do a browsing context ancestor walk and that might be okay as I think all fetches always require a fully active document, but would be nice to have that confirmed.

(I'm also assuming that auxiliary browsing contexts are not special here and behave like other top-level browsing contexts for the purposes of this.)

cc @youennf @whatwg/security

@mikewest

This comment has been minimized.

Copy link
Member

commented May 9, 2019

/cc @jkarlin for Chrome's experimental implementation.

@youennf

This comment has been minimized.

Copy link
Collaborator

commented May 9, 2019

Safari is partitioning service workers so that a service worker of an iframe B in a top level page A will be using the partition of top level page A.
This makes the loading more consistent in general (whether intercepted or not, the iframe loads will use the same partition) and improves on privacy.

@jkarlin

This comment has been minimized.

Copy link

commented May 9, 2019

Very interested. We'd like to mitigate security issues such as x-site search.

Chrome's experimenting with double keying by (top-frame origin, url) as well as triple-keying (top-frame origin, initiator origin, url). Triple keying protects caches of frames within a page from each other. The performance hit from double-keying seems reasonable at first glance, but it's important that we address x-origin prefetch in a multi-keyed cache world. We don't yet have data on triple-keying.

@wanderview

This comment has been minimized.

Copy link
Member

commented May 9, 2019

This issue should also consider the differences between partitioned http cache and partitioned origin storage. I believe webkit's default partitioning include both http and origin storage. I don't think the chrome experiment includes any origin storage partitioning, though.

@mnot

This comment has been minimized.

Copy link
Member

commented May 9, 2019

+1

It would be nice to try to factor out cache key computation to support not only this, but things like variants, etc.

@annevk

This comment has been minimized.

Copy link
Member Author

commented May 10, 2019

Mozilla is interested in partitioning other bits as well, but for this issue I'd like to focus solely on the HTTP cache. Some of the infrastructure we might be able to reuse for the other bits mentioned above, but I don't think there's any strong reason to couple them from the start.

@johnwilander

This comment has been minimized.

Copy link

commented May 10, 2019

WebKit also partitions LocalStorage on eTLD+1 and used to partition cookies up until a couple of months ago (now the same cookies for third parties are just blocked instead).

In the case of partitioned LocalStorage, it is also not persisted which makes into a slightly weird SessionStorage.

I think eTLD+1 makes a lot of sense for partitioning unless we’re seeing (or expect to see) attacks that would be fixed with origin partitioning. However, as Youenn said, we’d be willing to harmonize with other implementers for consistency.

@jkarlin

This comment has been minimized.

Copy link

commented May 10, 2019

I'm a proponent of origin as it's the security boundary for most aspects of the browser and easier to reason about.

/cc @sleevi

@annevk

This comment has been minimized.

Copy link
Member Author

commented May 10, 2019

Since the cache attacks are not that involved it seems rather risky to not do origin-based as it would mean a compromise of any example.com domain could be used to attack sensitive.example.com.

@jkarlin

This comment has been minimized.

Copy link

commented May 17, 2019

Another question is how we deal with x-origin <link rel=prefetch>. Which cache key does the prefetch use? If it winds up in the prefetching page's cache, it's a waste of network. But how do we know which key should be used?

I know of two options to make x-origin prefetch still work:

  1. Allow prefetched resources to be used once within 5 minutes after prefetching, regardless of the cache key. This opens a one-way communication channel between the page that prefetched the resources and the one that consumes them.

  2. Allow prefetched resources to be used once regardless of cache key so long as the page loading the resource was navigated to directly (for some definition of directly) by the page that performed the prefetch. This also forms a one-way communication channel between the page that prefetched and the one that used it, but they had a channel available anyway (link decoration).

/cc @yoavweiss @kinu

@youennf

This comment has been minimized.

Copy link
Collaborator

commented May 17, 2019

@jkarlin, there is an on-going implementation of prefetch with double key caches in WebKit.
So far, the implementation does not take into account which page is consuming the prefetch.
#881 is related.

@jkarlin

This comment has been minimized.

Copy link

commented Jul 8, 2019

Great, let's leave the prefetch discussion in #881 then. We're still doing the work to compare performance of double vs triple keying the network stack. Sorry for taking so long. Note that we're planning on using this key for the entire network stack (memory cache, disk cache, socket pools, etc).

@shivanigithub

This comment has been minimized.

Copy link

commented Jul 16, 2019

In terms of a spec for the double keyed cache, would appreciate inputs on what's a good place to spec it, possibly the Fetch whatwg spec.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 16, 2019

@shivanigithub if you want to help with this that'd be great! My thinking here involved changes to the Fetch and HTML standards. In particular:

  • Change HTML such that it ends up exposing a "first-party origin" field on its environment settings object. This will likely require changes to document object creation and worker creation to store the state and changes to the environment settings object to expose it (similar to how we do it for other such state, such as referrer policy).
  • Change Fetch such that it copies a request's client's first-party origin on a new first-party origin field on the request object.
  • Change Fetch such that whenever it talks about "the HTTP cache" it instead gets an HTTP cache via the first-party origin somehow. I'm not sure how detailed we want to make this, but we probably want to at least have a couple of words describing what it means to get an HTTP cache for a particular origin. Perhaps this can borrow wording from how we deal with connections.

Hope that helps!

@sleevi

This comment has been minimized.

Copy link

commented Jul 16, 2019

@annevk I suspect we'd also need to update connection pools as well to extend that concept. Or were you thinking of doing it separately? I wasn't sure if #904 (comment) extended to those changes as well?

I ask, because I'm wondering if it makes sense if, similar to how "connection" is defined as an aggregate of both origin and credentials, it might make sense to define the concept as an aggregate function (which is made up of, for now, first-party origin, a singular value), which would then

  1. Allow you to extend the definition if there are other attribute keys (e.g. TBB uses the TOR circuit ID as part of the key, IIRC)
  2. Allow that concept to be reused between the "connection group" and "HTTP cache".

Incrementalism also works, I just wanted to make sure that was your goal.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 16, 2019

@sleevi I'd like changes to connections to be a separate change, but it does make sense to me to iterate toward that. Would you mind opening an issue on that and elaborate a bit on the thinking behind it there? I understood there to be an issue with sites being able to reach the global connection limit, but that would not necessarily disappear with a first-party origin key on connection pools I think.

@sleevi

This comment has been minimized.

Copy link

commented Jul 16, 2019

Filed #917. My understanding is that UAs doing this partitioning are doing so for privacy reasons, and hopefully #917 explains why those privacy reasons aren't functionally achievable without a similar partitioning/keying of the connection pool.

@shivanigithub

This comment has been minimized.

Copy link

commented Jul 17, 2019

@annevk Thanks for the inputs. Looking into these.

@shivanigithub

This comment has been minimized.

Copy link

commented Jul 25, 2019

@annevk Regarding the spec inputs, am I correct in understanding that the proposed "first-party origin" field on the the environment settings object is an output field populated by the browser to indicate the key being used and not an input to the browser?

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 26, 2019

I'm not entirely sure what you mean, but yes, the browser (i.e., user agent) is responsible for setting it.

@shivanigithub

This comment has been minimized.

Copy link

commented Aug 9, 2019

Few clarifications for spec changes:
Chrome's experimenting with double keying (top-frame origin, url) as well as triple-keying (top-frame origin, frame origin, url). From a spec perspective how much in detail do we want to go in the contents of the partitioning key?
E.g. in the fetch spec, would something like this make sense:

[Already existing text]
A request has an associated cache mode, which is "default", "no-store", "reload", "no-cache", "force-cache", or "only-if-cached". Unless stated otherwise, it is "default".

[New text added following the above]
The user agent might partition the HTTP cache using a partitioning key and references to the HTTP cache in this spec refer to a partitioned cache, when applicable. If the cache is partitioned, it will be looked up using the request URL and the top-frame origin (and possibly also the frame origin) instead of just the request URL.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Aug 12, 2019

I think at the very least we should define top-level origin from first principles and use that as the key as all browsers plan to align on that. Allowing additional keys seems reasonable. I also think we should be more explicit and update the various lookup points to pass in the appropriate keys.

@robmadole

This comment has been minimized.

Copy link

commented Aug 26, 2019

Hey all. We operate some CDNs for Font Awesome and have questions about partitioning the cache. Is this the appropriate audience to ask?

In general, for CDN operators who benefit from a shared non-partitioned cache will this change negate those benefits? An example would be site A loads CDN resource X which has a very long cache-control header. When site B loads CDN resource X it already exists in the browser's cache and doesn't need another network fetch.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Aug 26, 2019

As reported by Shivani for Chrome at https://groups.google.com/a/chromium.org/d/msg/blink-dev/6KKXv1PqPZ0/3_1nYzrBBAAJ and matched by Firefox's measurements while that is a theoretical concern in practice users don't hit that scenario a lot.

@ericlaw1979

This comment has been minimized.

Copy link

commented Aug 26, 2019

Rob's question is an interesting one, and I think it's important to be explicit about what we know and what we don't know.

To the question of "does this change impact a CDN operator who benefits from a shared non-partitioned cache", the answer is clearly yes-- the benefit of a shared cache goes away when the cache isn't shared. Reuse of a resource from a cross-site context will no longer be possible when cache partitioning takes effect.

Now, it's also fair to point out that the Chrome team's data suggests that, in total, the benefit of non-partitioned cache for a particular client is often small (reducing cache hit rate by ~4%, making the cache something like 10% less effective if the cache hit rate were ~40%.)

However, that end-user impact could look very different to the folks at FontAwesome. I'm haven't seen any data that reveals FontAwesome's current cache hit rate. It could be the case that, on average, each FontAwesome resource is reused on two different sites visited by their average user, in which case the new cache partitioning will double the bytes-on-wire load for the FontAwesome CDNs, even as that individual user themselves would only see a modest % increase in bytes-on-wire (because reused fonts represent only a small percentage of their traffic).

It might be interesting for the Chrome folks to do a study that breaks down the bytes-on-wire cost to the top reused websites (e.g. I predict Google Analytics, Google Fonts, Doubleclick etc are top hitters) so the impact on servers could be better reasoned about.

From your side, Rob-- does FontAwesome do anything that attempts to measure reuse across sites? E.g. you could conceivably change some percentage of your traffic to use a short lifetime Vary: Origin and/or and a Stale-while-revalidate cache-control directive, and watch your logs to get an upper-bound on how much reuse is occurring today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.