html
html copied to clipboard
Allowing top-level communication for cross-origin isolated documents
The current model of cross-origin isolation is incompatible with federated sign-in flows based on popups. Any popup opened by a document with a COOP of same-origin will not be able to communicate with its opener, preventing passing information to the application to which the user wants to sign in (or, commonly, to the identity provider's iframe embedded by that application).
Some background for this decision is in https://github.com/whatwg/html/issues/3740#issuecomment-417469433 and the subsequent discussion.
Based on discussions with developers, it looks like this can become a barrier to adoption of cross-origin isolation and to efforts to enforce better isolation by default. We should give developers a recommended solution for this use case which will not require them to re-architect their applications to remove cross-origin isolation from parts of their application where the user is able to sign in.
The main difficulty is that due to browsers' efforts to disable the sharing of state across storage partitions, APIs which could have potentially been used as a fallback to allow the popup to communicate with its opener (BroadcastChannel, localStorage) are unlikely to be tractable approaches in the long term.
A few possible alternatives:
- Allow
postMessageto be used in situations where COOP caused a browsing context group switch.- This seems awkward in the current design of COOP, but it would be the simplest approach from developers' point of view, because it wouldn't require changes to their client-side code. It also doesn't have cross-site tracking potential to the same extent as other "origin-wide" APIs, such as
localStorageorBroadcastChannel.
- This seems awkward in the current design of COOP, but it would be the simplest approach from developers' point of view, because it wouldn't require changes to their client-side code. It also doesn't have cross-site tracking potential to the same extent as other "origin-wide" APIs, such as
- Build exemptions into the partitioning of BroadcastChannel to allow it to deliver messages between the popup and a same-origin iframe embedded by its opener.
- This would require defining a set of criteria that would be met by legitimate scenarios (e.g. sign-in flows), but which would not allow BroadcastChannel to be used for cross-site tracking. My guess is that this is doable, but may be difficult to justify in a principled way, i.e. any partitioning exemptions would seem somewhat arbitrary.
- Ship WebID.
I do think that something like WebID could be a good long-term solution, but I'm worried that without a short/medium-term alternative we'll make life difficult for developers; an approach like (1) or (2) above could possibly be a reasonable alternative. Given the increasing interest in cross-origin isolation it seems somewhat important for us to figure this out soon.
/cc @annevk @mikewest @camillelamy Any thoughts or other ideas here?
I think I'm missing how postMessage() doesn't have the same tracking potential.
postMessage() lets you communicate only with a window to which you have a reference (or, possibly in this case, would have had a reference if it wasn't for COOP). The other mechanisms let you share data between all same-origin windows, even if they are in unrelated browsing context groups (possibly restricted by storage partitioning; but at the very least with same-origin windows in other BCGs with the same storage key).
So, hypothetically, in a browser without storage partitioning an ad iframe can synchronize state across all 3p contexts with BroadcastChannel or localStorage, but not with postMessage(). (FWIW this doesn't necessarily make a qualitative difference here; but I could imagine that from a cross-site tracking perspective postMessage() may be less concerning.)
@annevk I agree that postMessage has tracking potential for cross-site cases, but I don't think they're quite the same. In the long-term, I think WebID or something similar is the answer. However, in the short term, I think leaving federated auth at postMessage is preferable to moving it to BroadcastChannel. Tracking with BroadcastChannel requires the two top-level sites be open concurrently at all. postMessage at least requires the documents reach each other. To track, you'd need to either wait for that to happen (which we can hopefully reduce over time) or you'd need to, e.g., visibly open a popup. That's still not great, hence WebID, but I think it's meaningfully better than the BroadcastChannel version.
Moreover, in the long-term, same-(top-level)-site cross-origin documents also have communication uses. In those cases, neither postMessage nor BroadcastChannel have a tracking concerns. For non-broadcast versions of those flows, I think there are good developer ergonomics and performance (wake up fewer documents) reasons to prefer postMessage.
Apart from the tracking concern there's also an architectural concern as otherwise same-origin documents would now only have postMessage() as communication channel, supposedly. Not to speak of the impact on browsing context groups, less bfcache opportunities, etc.
I'm probably missing something, but I don't think this would prevent same-origin documents from using the other APIs to communicate, as long as they're within the same storage partition; e.g. top-level same-origin documents could still share data via localStorage, etc. The goal here is to additionally allow certain kinds of same-origin communication across storage partitions, which isn't disallowed by cross-site tracking protections (you still have direct DOM access to cross-partition same-origin documents), but which is disallowed by cross-origin isolation (because you can no longer postMessage() to your popup).
I'm also curious about the other kinds of impact you mentioned above, it would be helpful to understand these concerns.
What I'm worried about is that without providing COI documents with a recommended API to communicate with their popups, it's likely that developers will use alternative mechanisms to achieve the same goal, e.g. use link decoration in the OAuth popup to redirect back to a document in the application's origin and then use a mechanism like localStorage to exchange data. This is going to be more clunky and will possibly conflict with other cross-site tracking measures in the future.
Say A opens A' and A' has COOP and A' and A are same origin. Today that means A doesn't have a WindowProxy for A', with this, I guess it would. But somehow only postMessage() would be available? Today, A and A' do not share a browsing context group and therefore have independent agent clusters. With this, unclear? Today, WindowProxy references are never shared outside a browsing context group. With this, unclear?
Yeah, no disagreement from me here: this would certainly require figuring out a way to pass data around between BCGs intentionally separated by COOP. I guess my question is whether poking a hole for postMessage and allowing it to work across BCGs would be reasonable, or whether -- for example -- it's more appealing to make exemptions for BroadcastChannel to let it work across storage partitions in some cases (or implement WebID, or ...)
I realize that both of the ideas above can be ugly (or turn out to not be feasible), but my guess is that we don't do anything the workarounds built by developers are going to be much worse in the long run.
Personally something like WebID seems more reasonable to me long term, but I'm also interested in seeing workarounds that would work in Safari (assuming that Safari ships COOP soonish).
This is definitely a possible approach, but practically it will mean that -- until WebID ships in most browsers -- authors of OAuth flows will have to switch to one of the workarounds like link decoration + top-level same-origin sharing of state.
Well, we discussed OAuth flows while designing COOP and same-origin-allow-popups and unsafe-none were always meant for those use cases.
We also discussed allowing postMessage() and there were several implementation realities that made this infeasible (though I think for Firefox we're mostly past that now, including on mobile), but I also don't think we really tried to figure out what it would mean. And at this point I'd rather not add more tools to the popup workflow as they cause issues for anti-tracking and bfcache.
I don't want to belabor the point because I agree with you about the background and the difficulty here. But we do have more information today than we did a couple of years ago, which can have a bearing on our decisions. Specifically:
- Cross-origin isolation is gaining developer interest beyond what we (or at least I personally) expected, including ideas to enable it as the web default. We can't expect COI to be a niche thing for which developers are willing to jump through significant hoops.
- Anti-tracking improvements (storage partitioning) are removing mechanisms that were possible alternatives for this use case at the time we decided we can punt on
postMessagesupport in COOP. Even if developers can still use workarounds (say, link decoration), it's likely that they aren't the right long-term approach and we shouldn't push developers in their direction.
Having postMessage work for the popup workflow actually seems like the most compelling option from an anti-tracking point of view. Anti-tracking efforts don't restrict postMessage with your popups; the fact that you can't use it from a COI context is an artifact of how we specced COOP, rather than being dictated by privacy considerations. It seems worthwhile to think about what workarounds developers will develop here (which I'm worried may be objectively worse from both a privacy and complexity point of view).
I think the fact that anti-tracking hasn't tackled popups (including postMessage()) yet is precisely because of OAuth making it hard, but everyone is well aware that they present loopholes that ought to be closed.
I have to say this is news to me; do you have a reference you could point to for this?
Also, I'd find this stance defensible if we had plans to break postMessage to popups from non-COI contexts, which doesn't seem like it's on the horizon? Otherwise we're just punishing developers who do the right thing and enable COOP+COEP.
Firefox has done some investigation here and I suspect we'll get back to it: https://bugzilla.mozilla.org/show_bug.cgi?id=1657250. It has come up in the Privacy CG a bunch too. And indeed that's why there is interest in WebID (though also wariness given the scope). (Saving grace of popups is that they require user activation, but that is not hard to come by.)
Thanks @annevk, this is helpful. Re: user activation, we could consider whether there are additional restrictions on the popup that would we could enforce to ensure anything we allow would only be usable for legitimate, i.e. non-tracking, use cases. For example, we could deliver messages only if the popup doesn't have a reference to any other window, require the popup to be same-origin with the document sending the message, etc (we'd have to be careful about this not causing an infoleak, but it should be doable).
My guess is that if we're planning to keep allowing postMessage() in non-COI contexts in the medium term, something like this could possibly be a workable interim solution until WebID or a better alternative ships. It wouldn't provide sites with anything more than non-COI documents can do already (and we could hopefully limit the scope, as mentioned above), and it could prevent the proliferation of workarounds that are more likely to conflict with upcoming anti-tracking work.
I really think having postMessage broken with COOP is going to make it hard to implement for a lot of modern web applications, which have been pushed toward the greater security guarantees it provides vs historical approaches. I appreciate the nod to WebID, but there are plenty of cases where secure cross-origin communication is required that are not auth related.
After a few conversations with @camillelamy and @arturjanc, I wonder if we could take an alternate approach to those proposed above by hardening COOP: same-origin-allow-popups until we considered it solid enough to enable cross-origin isolation (in combination with an appropriate COEP, just as today). If we could do that, we wouldn't need to break the window handle, and postMessage could continue to work, without asking developers to do additional work.
I think this hardening would boil down to allowing user agents to consistently process-isolate the newly opened window from its opener by breaking synchronous communication channels:
-
For cross-origin windows, the web platform doesn't provide any synchronous communication channels. Process isolation is therefore possible on all platforms today in Chrome, and should be possible across platforms in Firefox once Project Fission ships (or perhaps this part is already shipping?). This is the interesting core of the payments and sign-in use cases, so it's nice that it works.
-
For cross-origin-but-same-site windows, this could be possible if we tie a window's agent cluster to its origin if any COOP other than
unsafe-noneis asserted. This would break synchronous access patterns (viadocument.domainandWebAssembly.Module), bringing us to the same platform-level picture as cross-origin windows. This is similar to what's proposed in whatwg/html#6177. -
For same-origin windows, we'd need to break synchronous communication between COI and non-COI contexts. That could be accomplished by taking the COI status of the new window into account when assigning the new window to an agent cluster (making the window appear closed if it asserts
unsafe-none), or by doing something more dramatic, perhaps binding the COI status to the origin, much as we do with the origin's domain today? This direction is proposed in whatwg/html#6178.
This seems like a path that might be worth exploring.
To be clear, even if the top-level window is cross-origin, that doesn't mean that all agent clusters "in that window" are. If A1 popups B and B embeds A2, A2 can reach A1 through parent.opener. So I think it all comes down to how you would solve for that. (And it sounds like the proposal is to change the keying for agent clusters, presumably coupled with changing IsPlatformObjectSameOrigin, which seems sound, but also breaks new ground as @domenic notes.)
(I guess there's a larger question here of whether we want to encourage this pattern given the issues with popups.)
To be clear, even if the top-level window is cross-origin, that doesn't mean that all agent clusters "in that window" are.
Yes, I should have been more clear about that case, and I agree with you. I do think that changing the keying for agent clusters is a reasonable way of dealing with the issue, and I'm hopeful that this use case (which does seem like it's going to bite some folks trying to adopt COI) can motivate rekindling the conversation you're pointing to.
(I guess there's a larger question here of whether we want to encourage this pattern given the issues with popups.)
A related question is "How can applications that exist today adopt the security primitives we'd like them to adopt?" I think we're more likely to see more adoption if we can accommodate existing practice when possible. Paving cowpaths seems easier than asking the cows to hop into the Cow Transporter 2.0™ that we haven't actually figured out how to build yet. :)
/cc @csreis, as he's concerned about the same issue Anne noted.
Yes, I'll mainly share that the example Anne noted happened in practice, at least in the past. In https://crbug.com/128772 from 2012, we found that Facebook was using an iframe on a cross-origin page to open a Facebook OAuth popup and expected script calls between the iframe and popup. That's a hurdle for putting OAuth popups in their own process (without OOPIFs and Site Isolation).
Caveat: I don't know if there are still sites doing that or if we have alternatives to recommend for them, but it's one of the cowpaths Mike mentions, and one that caused serious bugs in Chrome in the past.
I think that Facebook was historically responsible for most of these weird domain-lowered synchronous cross-frame/window accesses and that code should all be gone. I think cross-origin popups and iframes that break all sync relations but could use postMessage only to the opener keeps alive most important use-cases. It would even be fine to break the ability to traverse to other reachable contexts like opener.parent and the ability for the opener to navigate or do anything but close the popup reference.
@abflow, I'd kindly ask you to confine your suggestions for novel web security models to your own issues, and not comment on other people's issues with them.
One possibility could be to apply the restrictions only when COEP is enabled - i.e. create a COOP of same-origin-allow-popups-plus-coep which enables crossOriginIsolated. Then we can treat the fact that all frames enabled COEP as an opt-in into the restrictions. After all, right now a frame with COEP can be loaded in a cross-origin isolated context where its Agent Cluster is already keyed to origin. In this context, it cannot interact synchronously with a same-origin frame in a page with a different COOP status, because there are no pages with a different COOP status in the browsing context group. So, if we only impose restrictions when you have COEP, we wouldn't be breaking functionality, and sites would still have a way to make their OAuth flows work as long as it uses PostMessage.
@camillelamy Can you clarify what restrictions you are referring to above, i.e. are you talking specifically about the agent cluster keying changes?
I think the idea is reasonable, but I'm wondering if we'd need to care about the fact that COEP only applies to the opener's frames, but not to the openee's frames. Compare:
- A [COOP: same-origin-allow-popups-plus-coep] iframes B1, opens B2 [COOP: unsafe-none] as a popup.
- A1 [COOP: same-origin-allow-popups-plus-coep] opens B [COOP: unsafe-none] as a popup; B iframes A2.
- A slight variant of the above: A1 [COOP: same-origin-allow-popups-plus-coep] embeds B1, opens A2 [COOP: unsafe-none] which embeds B2.
In the first case, B1 must have opted in by setting COEP, as you say. In the other cases, COEP is only enforced on the iframes of the opening window and not the popup. I don't think this is a problem because keying of the agent clusters would prevent the top-level windows from sharing a process, I just wanted to make sure we consider this.
Not only Oauth flows, but also if there are front-end SDKs used by third party sites(A), then the SAB usage restrictions need to be hacked like the below. Page 2's purpose is solely to enable the cross-origin interaction via postmessage because siteA-page1 enabled COOP+COEP to use SAB. Site B is say some page related to the front-end SDK's company(say like a AWS SDK or Facebook SDK etc)
SiteA-page1(COOP+COEP) <--interact via local storage/broadcastchannel-> popup to SiteA-page2(no COOP) <--interact via postmessage--> Popup to SiteB(no COOP).
Is there a better way to avoid multiple popups as shown above?
@arturjanc I am talking about both changes.
Basically, the idea is that we create a new value of COOP, same-origin-allow-popups-plus-coep. This is set when a top level document sends a Cross-Origin-Opener-Policy: same-origin-allow-popups header and a Cross-Origin-Embedder-Policy: require-corp header. When a page has a COOP value of same-origin-allow-popups-plus-coep, its browsing context can be crossOriginIsolated if the user agent supports crossOriginIsolation.
In pages with COOP same-origin-allow-popups-plus-coep, agent clusters are keyed to origin. This is exactly like with COOP same-origin-plus-coep pages.
However, to make the crossOriginIsolation status of COOP same-origin-allow-popups-plus-coep work, we need to add one extra restriction. That is, documents whose top-level browsing contexts have different crossOriginIsolated status cannot have synchronous access to each other, and should only have access to the cross-origin WindowProxy methods. Maybe we can achieve that through keying agent clusters on crossOriginIsolated status as well, or maybe we need to add the crossOriginIsolated status as a parameter to determine if documents are same-origin or not (I am not really sure of the right way to spec this behavior).
My argument is that those restrictions are ok to apply to cross-origin subframes of the same-origin-allow-popups-plus-coep, because those subframes have set COEP require-corp. Which means that they have already opted into being loaded in a same-origin-plus-coep page, which has the following restrictions:
- Agent clusters are keyed to origin.
- Communication with documents in pages with different crossOriginIsolated status is impossible due to browsing context group switches.
So the restrictions we are putting on COOP same-origin-allow-popups-plus-coep pages are a subset of the restrictions in same-origin-plus-coep pages, which should be fine. Similarly, while documents in a popup opened by the same-origin-allow-popups-plus-coep page would not be able to interact synchronously with documents in the same-origin-allow-popups-plus-coep page, this is still better than no interaction at all in the same-origin-plus-coep page.
Basically, I think these restrictions should be ok when all cross-origin subframes have COEP, which is the point of contention for applying them to COOP pages without COEP. Since this would fix a major problem with the crossOriginIsolated rollout, I think this is a good direction for us to go in.
@jyothsna The proposal I am discussing above would simplify your example. You would have SiteA(COOP same-origin-allow-popups + COEP) <--interact via postmessage--> Popup to SiteB(no COOP).
Hey folks, I have put together an explainer for allowing COOP same-origin-allow-popups + COEP to make pages crossOriginIsolated. @annevk @domenic I'd appreciate your feedback!
Some thoughts:
- It seems Chrome is also pursuing WebID quite aggressively. Do we need both? As I mentioned above, I'm extremely wary of adding new functionality to popups.
- I don't see anything there about IsPlatformObjectSameOrigin.
- Do we want to expose the other non-
postMessage()APIs? - Is this even implementable in browsers without site isolation? (If I remember correctly we didn't do this for COOP exactly because of that concern.)
Re: (1), based on the recent workshop on WebID, my impression was that the proposals for more fully browser-mediated identity experiences intended to be options and recognize that the existing set of identity flows are diverse and may never be fully replaced. There are also many use cases beyond WebID that still rely on the popup pattern. More sophisticated OAuth2 permission and sharing dialogs (richer than what the WebID mediation based flows imagine), as well as things like photo pickers, friend finders, etc. that rely on the postMessage pattern, as well. It is a great way to provide a user-guided experience for selective sharing.
I'm less concerned about (3), and even would be OK with removing the ability to do address anything but e.g. window.opener or window.parent (no parent.parent or parent.frames[]) but completely removing the ability to do any async communications between a popup and its opener when opted-in to Spectre protections (which I expect will be essentially mandatory) is really damaging to a wide set of web platform abilities and patterns in broad use today.
On Mon, Jun 21, 2021 at 3:41 AM Anne van Kesteren @.***> wrote:
Some thoughts:
- It seems Chrome is also pursuing WebID quite aggressively. Do we need both? As I mentioned above, I'm extremely wary of adding new functionality to popups.
- I don't see anything there about IsPlatformObjectSameOrigin.
- Do we want to expose the other non-postMessage() APIs?
- Is this even implementable in browsers without site isolation? (If I remember correctly we didn't do this for COOP exactly because of that concern.)
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/whatwg/html/issues/6364#issuecomment-864930033, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQVW4CNYFQEOI5PIRH35FDTT4JNBANCNFSM4XGIRJYQ .