diff --git a/README.md b/README.md index adecabf..f373127 100644 --- a/README.md +++ b/README.md @@ -110,22 +110,16 @@ Moving to origin isolation requires some observable changes, and thus the opt-in The specification for this feature in itself consists of two parts. One part is header parsing, which relies on the [Structured Headers](https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html) specification to do most of the work. The other is agent cluster keying, which is done by modifying the HTML Standard's [agent cluster map](https://html.spec.whatwg.org/#agent-cluster-map). -In particular, when creating a document, we use the following in place of the current algorithm for [obtain an agent cluster key](https://html.spec.whatwg.org/#obtain-agent-cluster-key). It takes as input an _origin_ of the realm to be created, _requestsIsolation_ (a boolean, derived from the presence of a valid `Origin-Isolation` header), and a browsing context group _group_. It outputs the [agent cluster key](https://html.spec.whatwg.org/#agent-cluster-key) to be used, which will be either a site or an origin. +In particular, when creating a document, we modify the algorithm to [obtain an agent cluster key](https://html.spec.whatwg.org/#obtain-agent-cluster-key). It takes as input an _origin_ of the realm to be created, _requestsIsolation_ (a boolean, derived from the presence of a valid `Origin-Isolation` header), and a browsing context group _group_. It outputs the [agent cluster key](https://html.spec.whatwg.org/#agent-cluster-key) to be used, which will be either a site or an origin. -1. Let _key_ be the result of [obtaining a site](https://html.spec.whatwg.org/multipage/webappapis.html#obtain-a-site) from _origin_. -1. If _key_ is an [origin](https://html.spec.whatwg.org/multipage/origin.html#concept-origin), then return _origin_. -1. If _group_'s [agent cluster map](https://html.spec.whatwg.org/#agent-cluster-map)\[_origin_] exists, then return _origin_. -1. If _requestsIsolation_ is true: - 1. If _group_'s [agent cluster map](https://html.spec.whatwg.org/#agent-cluster-map)\[_site_] exists, and _group_'s [agent cluster map](https://html.spec.whatwg.org/#agent-cluster-map)\[_site_] contains any agents which contain any realms whose [settings object](https://html.spec.whatwg.org/#concept-realm-settings-object)'s [origin](https://html.spec.whatwg.org/#concept-settings-object-origin) are [same-origin](https://html.spec.whatwg.org/#same-origin) with _origin_, then return _site_. - 1. Return _origin_. -1. Return _site_. +The new algorithm will check if _origin_ has previously been placed in a site- or origin-keyed agent cluster within _group_, and if so, it will always return that same key, to stay consistent. Otherwise, it uses the _requestsIsolation_ boolean to determine whether to return _origin_, or the derived site. -This algorithm has two interesting features: +The consistency part of this algorithm has two interesting features: * Even if origin isolation is not requested for a particular document creation, if origin isolation has previously created an origin-keyed agent cluster, then we put the new document in that origin-keyed agent cluster. -* Even when origin isolation is requested, if there is a site-keyed agent cluster with same-origin documents, then we put the new document in that site-keyed agent cluster, ignoring the isolation request. +* Even when origin isolation is requested, if there has previously been a site-keyed agent cluster with same-origin documents in the browsing context group, then we put the new document in that site-keyed agent cluster, ignoring the isolation request. -Both of these are consequences of a desire to ensure that same-origin sites do not end up isolated from each other. +Both of these are consequences of a desire to ensure that same-origin sites do not end up isolated from each other, even in scenarios involving navigating back and forward. You can see a more full analysis of what results this algorithm produces in our [scenarios document](./scenarios.md). diff --git a/scenarios.md b/scenarios.md index ef97f5e..818d537 100644 --- a/scenarios.md +++ b/scenarios.md @@ -17,10 +17,10 @@ Notes: | `https://e.com` w/ OI | `https://e.com` w/o OI | Both in `Origin{https://e.com}` | | `https://e.com` w/o OI | `https://e.com` w/o OI | Both in `Site{https://e.com}` | | `https://e.com` w/o OI | `https://e.com` w/ OI | Both in `Site{https://e.com}` | +| `https://e.com` w/o OI | `https://x.e.com` w/o OI | Both in `Site{https://e.com}` | | `https://e.com` w/o OI | `https://x.e.com` w/ OI | Main in `Site{https://e.com}`
Sub in `Origin{https://x.e.com}` | -| `https://e.com` w/o OI | `https://x.e.com` w/ OI | Main in `Site{https://e.com}`
Sub in `Origin{https://x.e.com}` | -| `https://e.com` w/ OI | `https://x.e.com` w/ OI | Main in `Site{https://e.com}`
Sub in `Origin{https://x.e.com}` | | `https://e.com` w/ OI | `https://x.e.com` w/o OI | Main in `Origin{https://e.com}`
Sub in `Site{https://e.com}` | +| `https://e.com` w/ OI | `https://x.e.com` w/ OI | Main in `Origin{https://e.com}`
Sub in `Origin{https://x.e.com}` | ## Three-document scenarios @@ -31,6 +31,56 @@ Notes: | `https://e.com`
w/ OI | `https://a.e.com`
w/o OI | `https://b.e.com`
w/ OI | Main in `Origin{https://e.com}`
A in `Site{https://e.com}`
B in `Origin{https://b.e.com}` | | `https://e.com`
w/o OI | `https://a.e.com`
w/o OI | `https://b.e.com`
w/ OI | Main and A in `Site{https://e.com}`
B in `Origin{https://b.e.com}` | + +## Session history scenarios + +The previous scenarios illustrate some cases where the proposed algorithm ignores the origin isolation request because a pre-existing site-keyed agent cluster exists for a same-origin URL in the current frame tree. The following scenario illustrates a case where the session history contributes to this calculation. + +### Navigating a subframe + +* Main frame: `https://e.com` w/ OI +* Subframe: `https://x.e.com` w/o OI +* Outcome (per above): Main in `Origin{https://e.com}` / Sub in `Site{https://e.com}` +* Historical map of agent cluster keys for this browsing context group: `(https, e.com, 443) => Origin{https://e.com}`, `(https, x.e.com, 443) => Site{https://e.com}` + +The user clicks a link in the `https://x.e.com` subframe which takes them to `https://e.org`. + +The user then clicks a button in the main frame which inserts a second subframe, pointing at `https://x.e.com`. But in the meantime the server operator has deployed origin isolation on `https://x.e.com`. Thus the scenario is now: + +* Main frame: `https://e.com` w/ OI +* Subframe 1: `https://e.org` (with `https://x.e.com` in the session history) +* Subframe 2: `https://x.e.com` w/ OI + +In this case, subframe 2 ends up keyed by `Site{https://e.com}`, because when loading `https://x.e.com`, we look up `(https, x.e.com, 443)` in the historical map of agent cluster keys, and see that it was originally allocated to `Site{https://e.com}`. + +This ensures that if the user navigates subframe 1 back, `https://x.e.com` again loads in `Site{https://e.com}`, as it did originally, and subframe 1 and subframe 2 are in the same `Site{https://e.com}` agent cluster. That is, we have avoided isolating same-origin pages from each other. And we've done so by using the rule of "first-seen agent cluster key wins", via the historical map of agent cluster keys. + +### Inserting iframes and saving JS references + +* Main frame: `https://e.com` w/ OI +* Subframe: `https://e.org` w/o OI +* Outcome (per above): Main in `Origin{https://e.com}` / Sub in `Site{https://e.org}`. +* Historical map of agent cluster keys for this browsing context group: `(https, e.com, 443) => Origin{https://e.com}`, `(https, e.org, 443) => Site{https://e.org}` + +JavaScript code in the main frame goes through a variety of contortions: + +```js +// Save a reference to the sub-frame window. +window.savedFrame = frames[0]; + +// Now remove it from the DOM. +frames[0].frameElement.remove(); +``` + +Some time later, JavaScript code inserts a new subframe, again pointing at `http://e.org`. But in the meantime the server operator has deployed origin isolation on `https://e.org`. Thus the scenario is now: + +* Main frame: `https://e.com` w/ OI +* Subframe: `https://e.org` w/ OI + +Will the subframe get site-keyed, or origin-keyed? + +The answer is site-keyed. We only consult the historical map of agent cluster keys, which says that `(https, e.org, 443)` goes in `Site{https://e.org}`. The fact that the iframe was removed (so no corresponding browsing context exists in the browsing context group), or that the `Window` was saved (so that the realm/agent/agent cluster still exist) do not impact our decision-making process here. We always consult the historical map of agent cluster keys to make the decision. + ## Worked-out nested scenario The following is a more detailed scenario, involving more levels of nesting and dynamic insertion of new frames. It illustrates the same fundamental principles as the above examples, but it goes through them in more detail, which might be helpful.