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

Severing a document's opener relationship regardless of origin #10373

Closed
yoavweiss opened this issue May 29, 2024 · 31 comments · Fixed by #10394
Closed

Severing a document's opener relationship regardless of origin #10373

yoavweiss opened this issue May 29, 2024 · 31 comments · Fixed by #10394
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: cross-origin-opener-policy Issues and ideas around the new "inverse of rel=noopener" header

Comments

@yoavweiss
Copy link
Contributor

yoavweiss commented May 29, 2024

What problem are you trying to solve?

Some origins can contain different applications with different levels of security requirements. In those cases, it can be beneficial to prevent scripts running in one application from being able to open and script pages of another same-origin application.

In such cases, it can be beneficial for a document to ensure it has a null opener, even if the document that opened it is a same-origin one.

It'd be great if COOP included a value that enabled that.

What solutions exist today?

There are no solutions today to solve this AFAIK.

How would you solve it?

By adding a no-opener-allow-popups value to the Cross-Origin-Opener-Policy header, that results in a null opener when calling creating a new top level travesable.

Anything else?

No response

@yoavweiss yoavweiss added addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest labels May 29, 2024
@yoavweiss
Copy link
Contributor Author

/cc @camillelamy

@annevk
Copy link
Member

annevk commented May 29, 2024

It seems a bit unfortunate that the header starts with Cross-Origin-*.

Also, I find omit rather vague given the current values. Are popups allowed for instance?

@yoavweiss
Copy link
Contributor Author

Also, I find omit rather vague given the current values. Are popups allowed for instance?

Maybe "noopener" would be a better value. From my perspective, popups should be allowed, as long as they have their opener relationship severed.

@yoavweiss yoavweiss changed the title An omit Cross-Origin-Opener-Policy value A Cross-Origin-Opener-Policy value that severs the opener relationship regardless of origin May 29, 2024
@yoavweiss yoavweiss changed the title A Cross-Origin-Opener-Policy value that severs the opener relationship regardless of origin Severing a document's opener relationship regardless of origin May 29, 2024
@annevk
Copy link
Member

annevk commented May 29, 2024

I think I understand what you mean, but that's a confusing comment given the current set of values. As in, same-origin-allow-popups explicitly does not break the relationship with any popups. It only breaks the incoming cross-origin relationship, if any.

To date we have only used noopener for outgoing relationships, but it might still be reasonable.

I think the other bit that's missing here is some kind of rationale as to why we would want to invest in this capability.

@yoavweiss
Copy link
Contributor Author

I think the other bit that's missing here is some kind of rationale as to why we would want to invest in this capability.

Fair, I augmented the OP a bit. Let me know if that's sufficient to understand the motivation.

@annevk
Copy link
Member

annevk commented May 29, 2024

I think that justifies incoming but not outgoing. It also raises some other questions:

  • What about embedding?
  • What about channels that are still available, such as storage, BroadcastChannel, shared workers, etc?

@yoavweiss
Copy link
Contributor Author

I think that justifies incoming but not outgoing

True. Thinking through this, I agree that it doesn't matter for the use case that outgoing opener relationships would be severed.

  • What about embedding?

CSP frame ancestors's value of 'none' allows sensitive apps to prevent themselves from being framed by other same-origin apps.

It's true that there may be cases where a frame may want to force itself to be sandboxed from the embedder. (in cases where it needs to be framed by some same-origin apps, but not directly scripted by them)

  • What about channels that are still available, such as storage, BroadcastChannel, shared workers, etc?

Those are presumed to be fine as communication between the different apps is permitted. (they are still the same origin)

@yoavweiss
Copy link
Contributor Author

I think I understand what you mean, but that's a confusing comment given the current set of values. As in, same-origin-allow-popups explicitly does not break the relationship with any popups. It only breaks the incoming cross-origin relationship, if any.

To date we have only used noopener for outgoing relationships, but it might still be reasonable.

Changed to OP to propose the value to be no-opener-allow-popups. Let me know if that's clearer.

@yoavweiss
Copy link
Contributor Author

After some prototyping, I'm now less certain that this can be achieved without an opt-in from the opener.

Given that window.open() is sync, and that COOP headers are received later on, it's unclear to me we can sever the relationship from the opener to the openee synchronously.

Maybe we can somehow severe it after the headers are received, but I'm not sure how that would look like without creating race conditions.

/cc @camillelamy @ArthurSonzogni

@annevk
Copy link
Member

annevk commented Jun 3, 2024

The opener would have a reference to a closed initial about:blank. That's the same as with COOP today, no?

@ArthurSonzogni
Copy link
Member

it's unclear to me we can sever the relationship from the opener to the openee synchronously.

A "frame" can't stand without a document. So when creating an <iframe> or a popup, they are both starting from the initial empty document. Creating the pair of frame and its initial document is always synchronous.

This is only after a subsequent navigation (always asynchronous) that we start receiving headers and can decide to instantiate the next document in a different browsing context group.

Maybe we can somehow sever it after the headers are received, but I'm not sure how that would look like without creating race conditions.

From the implementation or specification point of view?
Modifying ShouldSwapBrowsingInstanceForCrossOriginOpenerPolicy in your patch seems right. Hopefully, the COOP implementation can be reused.

@smaug----
Copy link

So how should this work if a new window is first opened with page A and then later navigated to B and only B uses the new header? The Window(Proxy) A (and B?) uses may have plenty of other references than the opener relationship at that point.

@yoavweiss
Copy link
Contributor Author

So how should this work if a new window is first opened with page A and then later navigated to B and only B uses the new header? The Window(Proxy) A (and B?) uses may have plenty of other references than the opener relationship at that point.

I think that would be similar to the opener relationship when page A opens a same-origin B, which then navigates to a cross-origin document.

@yoavweiss
Copy link
Contributor Author

I think that would be similar to the opener relationship when page A opens a same-origin B, which then navigates to a cross-origin document.

That's inaccurate. What I should've said is that it would be similar to the opener relationship when page A with a same-origin COOP opens a same-origin B with same-origin COOP, which then navigates to a same-origin document C with a unsafe-none COOP.

@smaug----
Copy link

ok, and how does "noopener" in the new value hint about that behavior? Isn't the change you want a tweak to https://html.spec.whatwg.org/#matching-coop so that in some cases that same origin check wouldn't be done (and nothing to do with noopener as such)?

@yoavweiss
Copy link
Contributor Author

That's indeed what I did in https://github.com/whatwg/html/pull/10394/files

@annevk
Copy link
Member

annevk commented Jun 7, 2024

I think what @smaug---- is getting at is that he doesn't find noopener a clear name for severing the incoming relationship as it has thus far only been used to sever the outgoing relationship. However, I'm not sure what he would prefer instead. I personally find noopener[-allow-popups] much clearer than the initially proposed omit, but maybe there is something better?

@smaug----
Copy link

That, and also this feels like a distinct feature of COOP itself, just like the existing noopener is a feature of its own.

@yoavweiss
Copy link
Contributor Author

Looking at the definition: "A cross-origin opener policy value allows a document which is navigated to in a top-level browsing context to force the creation of a new top-level browsing context, and a corresponding group"

That seems to be what we want here. Beyond that, we want to prevent the opener from being able to script the document in question. So to me, this very much feels related.

I hesitated a bit on the Report-only mode and how it translates, but after thinking about it, it does seem like something we'd want in order to facilitate deployment here (just like for COOP).

Happy to discuss this further :)

@smaug----
Copy link

But noopener itself is already a separate functionality in the platform. Is there a reason to not let opened page pages control opener relationship without binding that functionality to COOP.
I can see use cases, at least optimizations, for noopener without COOP. The page could that way try to optimize process usage in browsers, since they are more likely to use separate process when there is no opener relationship. And even more importantly bfcache requires noopener.

@annevk
Copy link
Member

annevk commented Jun 20, 2024

What additional functionality does COOP have? I thought this was it.

@smaug----
Copy link

smaug---- commented Jun 20, 2024

We discussed about this, and I can live with this. But this needs some documentation outside the normal COOP parts so that people trying to optimize for example bfcache handling can realize there is a way to break opener relationship also from openee side.

(Still feels like mixing two different features conceptually, when noopener from caller side is a separate thingie)

@annevk
Copy link
Member

annevk commented Jun 20, 2024

Why does that documentation concern not apply to COOP generally?

@annevk annevk added the agenda+ To be discussed at a triage meeting label Jul 1, 2024
@smaug----
Copy link

It does. But having something called Cross-Origin-Opener-Policy being possibly in a critical path on enabling bfcache even on same origin pages is a bit confusing.

@annevk
Copy link
Member

annevk commented Jul 1, 2024

I don't think this value necessarily helps with bfcache though? In particular it still allows the document to open its own popups, which would end up invalidating its cache entry as I understand it.

@smaug----
Copy link

Right, but you have the existing noopener for those cases.

@annevk
Copy link
Member

annevk commented Jul 3, 2024

I guess for bfcache the initial idea of noopener as a value that applies to incoming and outgoing would be quite useful then. If it's indeed the case that bfcache only works if your browsing context group only holds a single top-level browsing context at a time (which sounds about right).

@annevk
Copy link
Member

annevk commented Jul 5, 2024

So two things that came up yesterday:

  • As mentioned above having noopener as a value would be somewhat useful to be able to guarantee bfcache eligibility. cc @rubberyuzu @fergald
  • We need to figure out if this should relate to COEP. This seems somewhat tricky, but I do worry that if we don't explore it now we'll regret it later. cc @camillelamy

@past past removed the agenda+ To be discussed at a triage meeting label Jul 9, 2024
@yoavweiss
Copy link
Contributor Author

  • As mentioned above having noopener as a value would be somewhat useful to be able to guarantee bfcache eligibility. cc @rubberyuzu @fergald

Should this be a blocker? Or something we can expand to in a separate PR?

  • We need to figure out if this should relate to COEP. This seems somewhat tricky, but I do worry that if we don't explore it now we'll regret it later. cc @camillelamy

I wonder if @arturjanc or @estark37 have opinions here as well.

From my perspective, it seems prudent to start off with this not impacting the crossOriginIsolated state, and then potentially change it once we're convinced it's safe to do so. That would be a backwards compatible change AFAICT.

@yoavweiss yoavweiss added the agenda+ To be discussed at a triage meeting label Jul 12, 2024
@past past removed the agenda+ To be discussed at a triage meeting label Jul 18, 2024
@ArthurSonzogni
Copy link
Member

WHATNOT
@yoavweiss will ask @arturjanc and @ArthurSonzogni to comment on the #10373 issue.

I'm happy with the current proposal. Its implementation is almost the same as same-origin-allow-popups, except the "same-origin" part removal, which makes it trivial to implement and maintain.

Regarding its interaction with COEP and process isolation, I agree that taking the most restrictive approach initially is wise (e.g. not giving any new capabilities). We can always loosen restrictions later if needed.

I echo the concerns about potential developer misunderstandings regarding noopener-allow-popups. While it severs the opener/openee relationship, it's crucial to emphasize that it does not create a secure sandbox between same-origin documents. Web security primarily focuses on cross-origin threats, and assuming strong same-origin isolation would be a dangerous assumption.

I'm glad to see a disclaimer has been added to the spec PR, highlighting that noopener-allow-popups offers no security guarantees between same-origin documents. Developers must be reminded to avoid including or executing untrusted content on their origin, regardless of this feature.

I read the discussion about its potential benefits for BFCache, and Yoav's question about any potential delays or blockers this might introduce. My understanding is that this proposal creates more opportunities for BFCache utilization, as no known implementations support multiple BrowsingContexts within the same BrowsingContextGroup. This seems like a clear collateral win, without any drawbacks or necessary modifications to the proposal itself.

@yoavweiss yoavweiss added the agenda+ To be discussed at a triage meeting label Jul 30, 2024
@arturjanc
Copy link

We need to figure out if this should relate to COEP. This seems somewhat tricky, but I do worry that if we don't explore it now we'll regret it later. cc @camillelamy
I wonder if @arturjanc or @estark37 have opinions here as well.

IIUC the proposed COOP mode is more restrictive than COOP same-origin because it severs both the relationship to any popups and to the window's opener. So, at least at first glance, it should be safe to allow documents with this COOP value to unlock the crossOriginIsolated state (if combined with COEP).

That said, I haven't fully thought through the interactions between different COOP modes, so there's a chance that there are tricky edge cases here. As @yoavweiss mentioned above, starting without unlocking crossOriginIsolated is backwards-compatible; in the future, if we can convince ourselves that this is indeed safe (i.e. that there's no situation in which this value is more permissive than COOP same-origin), we can always relax the restriction and let it enable cross-origin isolation.

@past past removed the agenda+ To be discussed at a triage meeting label Aug 13, 2024
domfarolino pushed a commit that referenced this issue Sep 12, 2024
This is a refactor-only change, that serves as a precursor to #10394, and makes progress on #10373.
@annevk annevk added the topic: cross-origin-opener-policy Issues and ideas around the new "inverse of rel=noopener" header label Oct 7, 2024
@annevk annevk closed this as completed in 60d1874 Oct 8, 2024
dizhang168 pushed a commit to dizhang168/html that referenced this issue Oct 28, 2024
This is a refactor-only change, that serves as a precursor to whatwg#10394, and makes progress on whatwg#10373.
dizhang168 pushed a commit to dizhang168/html that referenced this issue Oct 28, 2024
Some origins can contain different applications with different levels of security requirements. In those cases, it can be beneficial to prevent scripts running in one application from being able to open and script pages of another same-origin application.

In such cases, it can be beneficial for a document to ensure its opener cannot script it, even if the opener document is a same-origin one.

This adds a noopener-allow-popups Cross-Origin-Opener-Policy value that severs the opener relationship between the document loaded with this policy and its opener. At the same time, this document can open further documents (as the "allow-popups" in the name suggests) and maintain its opener relationship with them, assuming that their COOP policy allows it.

Explainer: https://gist.github.com/yoavweiss/c7b61e97e6f8d207be619f87ab96ead5.

Fixes whatwg#10373.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: cross-origin-opener-policy Issues and ideas around the new "inverse of rel=noopener" header
6 participants