You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Disowning owner should perhaps affect link targeting #313
<div onclick="w = window.open('http://example.com', 'foo'); w.opener= null">
Click me first
</div>
<div onclick="w = window.open('http://example.org', 'foo'); w.opener= null">
Click me second
</div>
I believe per spec clicking the first link then the second one should only open one window, since disowning the owner doesn't affect link targeting as far as I can tell.
In both Gecko and Blink, two windows are opened instead.
In Edge only one window is opened and the second click doesn't navigate it (no matter what I do with the opener) which seems a bit odd.
When I do <a target=x href="data:text/html,<script>alert(opener)</script>">test</a> in Firefox I get a modal dialog asking whether I want to let the domain containing that link to control this tab. In Chrome this throws a security error of sorts rather than simply returning null.
Anyway, it seems pretty clear that not having an opener should affect link targeting.
I do get the same set of cookies if open about:blank with or without rel=noreferrer but there is no way to inspect this other than through the developer console. So about:blank inheriting a bunch of stuff should likely happen either way, although it is rather pointless since if you cannot access the window anymore you cannot navigate it anywhere or inject any kind of content.
window.name also seems preserved. Which makes it a one-way communication channel. Should we disable that for noopener or is that fine? I suspect folks might want to leak data to ads through other means than just Referer...
In an ideal world, I'd like to get to a place where noopener and noreferrer make it possible to put the new window in a completely separate process, even for same-origin documents. That means there must be no mechanism to gain direct DOM access to another same-origin window. With that in mind:
This seems like correct behavior to me. We want to decouple these windows, so they shouldn't be familiar with each other. If y'all agree, we'll need to change the "familiar with" definition to adjust the same-origin bit to exclude this case.
Chrome throws an error because we treat data: as a unique origin.
window.name also seems preserved
It would be good to prevent this, as it would enable the opened window to gain access to a cooperative opener. I'd like to prevent this in the same way we'd prevent targeting the one window from the other.
data:text/html,Click meAnd then click me
Wouldn't the targeting change fix this? That is, "foo" != "foo" if the windows aren't familiar with each other.
In blink, we only do the lookup by frame name in the local process. So in all cases where we host the navigation in a different process, the lookup by name just never works.
Agreed and that is what this issue is about. However, that does not mean that the browsing context name cannot be set for (what will be) a different process.
I talked with @bzbarsky and we would be okay with changing our behavior for the same-origin case
Specifically, I would be OK with changing to a behavior that is (1) unambiguously specified (which I don't think the current spec is, nor is Chrome's "local process" thing, since nothing defines what does and doesn't share processes in Chrome, and in fact it depends on various runtime things like how many processes are live already, last I checked) and (2) very likely to actually be web-compatible (because I don't want to change this behavior more than once).
Put another way, we need to prevent targeting by name in the same process for same-origin stuff in some cases to have a well-defined spec here that doesn't depend on arbitrary implementation details.
Gecko's current behavior is as follows, ignoring the special _blank, _parent, _top names:
First, we define a CanAccess primitive which takes as input two browsing
contexts: a target and a source. It is implemented as follows:
If no source provided (not sure whether this can happen in a web context), return true.
If source and target are the same object, return true.
Browsing contexts can target themselves.
If source is a nested browsing context and target is an ancestor of source and target is a top-level browsing context, return true.
Frames can target their top-level browsing context.
If source's active document is same-origin with the active document of target or some ancestor browsing context of target, return true. There are some complications here around file:// URIs.
Documents can target documents that are same-origin or nested through same-origin documents. Except that's not quite what this implements, because it walks browsing context parent chains, not nesting chains. But maybe we don't reach this for browsing contexts that are nested through inactive documents...
If target is not a toplevel browsing context, return false.
Can't target subframes in cases not covered above.
If target is not an auxiliary browsing context, return false.
Can't target random non-same-origin top-level browsing contexts.
Repeat steps 1-4 with the same source but target set to target's window's opener's browsing context, if target's window has an opener. This can be affected by .opener = null calls, so doesn't match the concept of "opener browsing context" in the spec, I think! Might return from this algorithm.
Can target an auxiliary browsing context if we can target its opener But this only goes back "one level", so to say: we never examine the opener's opener.
Return false.
Note that I can't claim that this CanAccess is at all principled. It sort of
started out as return true and then various restrictions were added to it to
prevent specific attacks while trying to not break web compat. It might well be
too tight or too loose or both in various cases.
Armed with this CanAccess, we can define IsValidTarget which takes a browsing
context "source", a browsing context "target", and a string "name" and does:
If target's name is not "name", return false.
If CanAccess(target, source) returns false, return false.
Return true.
the named target search for a string "name" now works like this:
Set "source" to be the source browsing context for the search. For targeted
form submissions and link clicks this is the browsing context of the node's
document. For window.open this is the browsing context of the "this" object.
Though there is some weirdness around the entry global's browsing context in
here too, to decide whether we're opening a new window. Chances are, there are
bugs around this stuff when document.domain is involved, in Firefox.
Check whether IsValidTarget(source, source, name). If true, return source.
For all descendants of "source", in depth-first preorder, check whether IsValidTarget(source, descendant, name). If true, return descendant.
Repeat the search for all ancestors of "source", in each case skipping all
browsing contexts we have already considered and doing depth-first preorder
walks on the browsing context tree. If any browsing context there returns true
from IsValidTarget(), return it. So this considers the parent of "source", then
all the parent's descendants that we haven't looked at yet, then the
grandparent, then all its descendants, etc.
If nothing has been found so far, repeat the walk starting at all the
toplevel browsing contexts in the same unit of related browsing contexts, in
some order. Again, check IsValidTarget each time, return if something is found.
Thanks for writing this up! It's good to know that my understanding of our algorithm wasn't too far off :-)
If source's active document is same-origin with the active document of target or some ancestor browsing context of target, return true. There are some complications here around file:// URIs.
* Documents can target documents that are same-origin or nested through same-origin documents. Except that's not quite what this implements, because it walks browsing context parent chains, not nesting chains. But maybe we don't reach this for browsing contexts that are nested through inactive documents...
For inactive documents here, are your referring to documents in the BFCache? IIRC currently we consider documents framed by a cached document to not have a parent, meaning that they wouldn't be able to target their _top. We might still be able to target auxiliary browsing contexts, however.
The above algorithm also needs to be influenced by window.close() as that'll remove a browsing context from consideration despite it not being discarded yet. (#4402 adds an "is closing" boolean for this additional branch.)
Activity
mikewest commentedon Nov 5, 2015
I prefer Gecko and Blink's current behavior, FWIW. That is, I agree that the spec should change.
Fix #313: make disowning disown the opener browsing context too
annevk commentedon Nov 13, 2015
I also get two windows for
and if I remove
rel=noreferrerI no longer do.When I do
<a target=x href="data:text/html,<script>alert(opener)</script>">test</a>in Firefox I get a modal dialog asking whether I want to let the domain containing that link to control this tab. In Chrome this throws a security error of sorts rather than simply returning null.Anyway, it seems pretty clear that not having an opener should affect link targeting.
I do get the same set of cookies if open
about:blankwith or withoutrel=noreferrerbut there is no way to inspect this other than through the developer console. Soabout:blankinheriting a bunch of stuff should likely happen either way, although it is rather pointless since if you cannot access the window anymore you cannot navigate it anywhere or inject any kind of content.window.namealso seems preserved. Which makes it a one-way communication channel. Should we disable that fornoopeneror is that fine? I suspect folks might want to leak data to ads through other means than justReferer...annevk commentedon Nov 13, 2015
So @bzbarsky points out that an important factor here is same-origin vs cross-origin. E.g., in Gecko today
would likely let the javascript URL read all the inherited stuff from the
about:blankcontext, even withrel=noreferrer.mikewest commentedon Nov 14, 2015
In an ideal world, I'd like to get to a place where
noopenerandnoreferrermake it possible to put the new window in a completely separate process, even for same-origin documents. That means there must be no mechanism to gain direct DOM access to another same-origin window. With that in mind:This seems like correct behavior to me. We want to decouple these windows, so they shouldn't be familiar with each other. If y'all agree, we'll need to change the "familiar with" definition to adjust the same-origin bit to exclude this case.
Chrome throws an error because we treat
data:as a unique origin.It would be good to prevent this, as it would enable the opened window to gain access to a cooperative opener. I'd like to prevent this in the same way we'd prevent targeting the one window from the other.
Wouldn't the targeting change fix this? That is,
"foo" != "foo"if the windows aren't familiar with each other.annevk commentedon Nov 16, 2015
I talked with @bzbarsky and we would be okay with changing our behavior for the same-origin case, to also not allow targeting by name there.
That would mean that the "familiar with" clause needs to change to "Either A is same-origin with B and neither A nor B is disowned, or", correct?
What is the reason for not setting
window.name? How can a cooperative opener allow access?jeisinger commentedon Nov 16, 2015
In blink, we only do the lookup by frame name in the local process. So in all cases where we host the navigation in a different process, the lookup by name just never works.
Ideally, that would be spec'd somewhere :)
annevk commentedon Nov 16, 2015
Agreed and that is what this issue is about. However, that does not mean that the browsing context name cannot be set for (what will be) a different process.
jeisinger commentedon Nov 16, 2015
right
bzbarsky commentedon Nov 16, 2015
Specifically, I would be OK with changing to a behavior that is (1) unambiguously specified (which I don't think the current spec is, nor is Chrome's "local process" thing, since nothing defines what does and doesn't share processes in Chrome, and in fact it depends on various runtime things like how many processes are live already, last I checked) and (2) very likely to actually be web-compatible (because I don't want to change this behavior more than once).
bzbarsky commentedon Nov 16, 2015
Put another way, we need to prevent targeting by name in the same process for same-origin stuff in some cases to have a well-defined spec here that doesn't depend on arbitrary implementation details.
Fix #313: make disowning disown the opener browsing context too
Fix #313: make disowning nullify the opener browsing context
annevk commentedon Nov 16, 2015
I updated the patch in #313 to do that. I also posted an update there on the test front: #323 (comment). Input appreciated.
Fix #313: make disowning a browsing context work
26 remaining items
bzbarsky commentedon Feb 5, 2018
annevk commentedon Feb 5, 2018
annevk commentedon Sep 26, 2018
Restrict browsing context lookup by name to frames that are related t…
bzbarsky commentedon Jan 11, 2019
Gecko's current behavior is as follows, ignoring the special
_blank,_parent,_topnames:First, we define a
CanAccessprimitive which takes as input two browsingcontexts: a target and a source. It is implemented as follows:
.opener = nullcalls, so doesn't match the concept of "opener browsing context" in the spec, I think! Might return from this algorithm.Note that I can't claim that this
CanAccessis at all principled. It sort ofstarted out as
return trueand then various restrictions were added to it toprevent specific attacks while trying to not break web compat. It might well be
too tight or too loose or both in various cases.
Armed with this
CanAccess, we can defineIsValidTargetwhich takes a browsingcontext "source", a browsing context "target", and a string "name" and does:
CanAccess(target, source)returns false, return false.the named target search for a string "name" now works like this:
Set "source" to be the source browsing context for the search. For targeted
form submissions and link clicks this is the browsing context of the node's
document. For window.open this is the browsing context of the "this" object.
Though there is some weirdness around the entry global's browsing context in
here too, to decide whether we're opening a new window. Chances are, there are
bugs around this stuff when document.domain is involved, in Firefox.
Check whether
IsValidTarget(source, source, name). If true, return source.For all descendants of "source", in depth-first preorder, check whether
IsValidTarget(source, descendant, name). If true, return descendant.Repeat the search for all ancestors of "source", in each case skipping all
browsing contexts we have already considered and doing depth-first preorder
walks on the browsing context tree. If any browsing context there returns true
from
IsValidTarget(), return it. So this considers the parent of "source", thenall the parent's descendants that we haven't looked at yet, then the
grandparent, then all its descendants, etc.
If nothing has been found so far, repeat the walk starting at all the
toplevel browsing contexts in the same unit of related browsing contexts, in
some order. Again, check
IsValidTargeteach time, return if something is found.Return
null.mystor commentedon Jan 11, 2019
Thanks for writing this up! It's good to know that my understanding of our algorithm wasn't too far off :-)
For inactive documents here, are your referring to documents in the BFCache? IIRC currently we consider documents framed by a cached document to not have a parent, meaning that they wouldn't be able to target their
_top. We might still be able to target auxiliary browsing contexts, however.bzbarsky commentedon Jan 11, 2019
Yes, or just unloaded in general.
annevk commentedon Mar 4, 2019
The above algorithm also needs to be influenced by
window.close()as that'll remove a browsing context from consideration despite it not being discarded yet. (#4402 adds an "is closing" boolean for this additional branch.)Restrict browsing context lookup by name to frames that are related t…
Navigation and session history rewrite
Make named window lookup more precise and correct BCG swap logic
Make named window lookup more precise and correct BCG swap logic