Open johnwilander opened 1 year ago
Hi John, I've got some questions on this proposal.
If I understand correctly, this suggestion is specifically for the scenario where the site-isolation status ought to change after the embed obtains access to its unpartitioned cookies. E.g., top-level foo.com embeds bar.com, and both documents are in the same process; then bar.com requests storage access and reloads, giving the browser the opportunity to load the new document in a separate process. To put it another way, if the site-isolation status does not need to change, then this proposal isn't necessary. (I.e. if foo.com and bar.com are initially in separate processes anyway, then a call to document.requestStorageAccess()
doesn't require a reload before accessing sensitive unpartitioned cookies.)
With that in mind:
document.requestStorageAccess()
. If we require COOP, then no reload is necessary.
window.crossOriginIsolated
be true in order for a call to document.requestStorageAccess()
to resolve. That would also require the COEP header, if I understand correctly.document.reloadOnStorageAccess()
is needed, or how it differs from what can already be done via e.g. document.hasStorageAccess()
and location.reload()
. If it is solely to let the browser propagate the "has storage access" state to the new document (after the reload), note that #141 has a provision for this without requiring a new API (see "Changes to navigation" in the spec). If there is another reason or other desired behavior, can you clarify what it is?When evaluating this proposal, I think we should also keep in mind the priority of constituencies. I'm unconvinced that the performance wins of allowing an in-process cross-site iframe (before the document.requestStorageAccess()
call) outweigh the security, ergonomics, and performance benefits of the alternative (i.e. requiring that the embedded iframe starts isolated, at least in the cases where it needs to request storage access).
On further reading, I misunderstood COOP/COEP/crossOriginIsolated. Those are about loading resources in separate BrowsingContextGroups, rather than separate processes. (And iframes are necessarily in the same BCG as their embedder [even though they may be in separate processes], since they must be able to communicate - so COOP is only relevant for top-level documents.) So that alternative isn't viable.
I do still think that preemptively applying site isolation to sites that are likely to request storage access is a good idea, however. If the heuristic approach would lead to too many false positives, we could consider introducing a new response header (without which calls to document.requestStorageAccess
would automatically reject) which indicates "this document plans to request storage access". That way, the browser has a clear signal to load the document in a separate process if possible. (The "if possible" caveat is intentional; I don't think we want to break/remove this functionality on resource-constrained devices that cannot do site isolation.)
(That header idea feels somewhat related to my Supports-Loading-Mode: with-storage-access
header suggestion in https://github.com/privacycg/storage-access/issues/122#issuecomment-1325381400. If the server knows the script will request storage access, and can tell the browser so upfront, then the browser could load the document with storage access already granted if the requestStorageAccess call would automatically resolve, and otherwise, could load the document without storage access but with the requestStorageAccess method "enabled".)
Hi @johnwilander, sorry for taking a bit to get to this. I think this is an interesting proposal given the security properties we're trying to impose on storage access right now (including per-frame). On the other hand, @cfredric highlights some valid concerns that I'm struggling to balance against the benefits of this proposal.
My main concern is that SAA requirements for developers are difficult enough as they are, as we've taken steps to protect against tracking, prompt abuse, and lately cookie-based attacks. I'd like to avoid a "feature creep" adding more responsibilities to the API (e.g. being a control for site isolation) that will further restrict and complicate the API to the point where we might as well not ship it. So, in discussing this improvement, I want to stay grounded to the usefulness for developers.
With that said, this could fall into the "just beneficial enough but still usable" goldilocks zone, heavily depending on the actual utility this provides for site isolation. I think that will be the main thing to figure out.
Chris and I are not necessarily experts on site isolation but luckily we have a number of experts on Chrome that we consulted with, and that conversation brought up a few more points:
I think Chris already relayed these points at the last PCG call, but I wanted to reiterate them here for visibility. I've also copied this to folks internally and encouraged them to chime in.
To move things forward, I also discussed this with @annevk and @bvandersloot-mozilla and (without trying to speak for them) both seemed somewhat relaxed about the idea of requiring a reload for access to cross-site cookies. So, I can see us further discussing the design details for that. I'll start with a few (strong) opinions that touch on the points above:
On a closer read, I'm not particularly fond of the semantic change of document.requestStorageAccess
to not actually change the behavior of the current document and instead affect a future document. If it were an alternate function document.requestStorageAccessAndReload
that appeared to devs as a convenience function, then I'd be more on board.
As-is this breaks the following use-structure that I see as the easiest way to use the API:
A developer has some function code()
that they need storage access for.
document.requestStorageAccess()->then(code)
document.requestStorageAccess()->then(code)
.Tangentially, this cracks into something I've been thinking of lately: now that the has storage access lives on the environment
, is document
the right object for these functions to live on? If the answer is "no, window
makes more sense" then maybe requiring a document to reload makes more sense, i.e. by defining a document "has storage access" as the conjunction of the environment's "has storage access" value and a header on the document's HTTP response.
As is, I agree with Johann's first two strong opinions though: "this API should not mention site isolation in its name" and "we should move away from "implicit" storage access given to documents based on actions of previous documents".
I discussed this some more with colleagues and we're amenable to a more backwards-compatible change along the lines @bvandersloot-mozilla suggests. Either a new method or perhaps a dictionary with a navigate
member accepting a same-origin destination. The latter might already be a flow that many websites have whereby they show a partitioned view and once they get cookie access they navigate to the non-partitioned view.
The existing code requestStorageAccess()
path would then end up failing in the scenario where a) the embedded site is already loaded into the non-isolated process and b) only then does the user visit the embedded site in a top-level navigable.
Does that seem like something that could work?
We discussed this at the editor's call and I had some thoughts/concerns which I've since confirmed with some other folks on the Chrome side:
navigate
parameter and the associated navigation on developers, which will result in worse performance and overall UX for end users in cases where developers wouldn't need to navigate/reload. It definitely seems like an inversion of the Priority of Constituencies.It would be nice if instead we gave the developer the ability to deal with these rarer failures when they happen, by initiating a navigation on their own. My preferred method of doing this would be exposing the failure reason through a special exception that gets thrown after the user consented to the SAA prompt, e.g.
document.requestStorageAccess()
.then(() => loadCredentials())
.catch((e) => {
if (e.name == "SecurityError" && e.message.contains("navigate")) {
location.reload();
}
});
I agree with Ben's above point that this probably shouldn't magically affect the next document load (something that @cfredric and I had also been discussing) and instead we should probably require developers to go through the regular rSA flow again after they handled the error with a navigation (just this time being autogranted because they have the permission). This would also make things more compatible with the storage handle approach suggested in #102.
Discussing this with colleagues we could live with the specific exception option. I suggest we reuse "NoModificationAllowedError
" for this purpose. (Branching on message
is an extreme anti-pattern we should not encourage anywhere, for what it's worth.) When that exception is thrown, your request in principle succeeded, but you'll have to create a new document and call requestStorageAccess()
again in that new document in order to be able to use it. And of course that would have to happen within some reasonable timeframe, so the end user can actually be assumed to remember having made that particular decision.
Thanks Anne, that seems reasonable to me!
Apple WebKit is interested in exploring if we can allow browser engines to reload a cross-site frame after it is granted storage access through the Storage Access API. That would allow web engines on resource-constrained platforms to only use site isolation for sub frames with access to unpartitioned storage.
There is a difference in data leakage risk between cross-site frames with partitioned storage and cross-site frames with unpartitioned storage. It's most important to isolate documents with personal content, and personal content almost always implies unpartitioned storage. Put differently, being logged in almost always implies access to first-party cookies.
The switch to an isolated process could be done either by a mandatory frame reload on granted storage access (crude) or in a way that's controlled by JavaScript in the frame (perhaps more elegant). For the latter, imagine this for cross-site frame X:
document.hasStorageAccess()
and learns that it does not currently have access.document.requestStorageAccess()
.document.reloadOnStorageAccess()
.Two key things here:
document.reloadOnStorageAccess()
. This would forward information from X's partitioned state to its unpartitioned state which obviously has privacy implications. But it would allow for the frame reload to be part of a natural content flow.