-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Fix #313: make disowning disown the opener browsing context too #323
Conversation
@bzbarsky could you please review this? |
I would like to see changes like this come with web platform tests, and ideally the test results in various browsers. Especially because it's not immediately obvious which observable behavior is affected. I know link targeting is; is anything else? On the change itself, I think it would be better to just make it be a toplevel browsing context instead of indistinguishable from one, unless we have carefully audited the spec to make sure it never simply switches on the browsing context type. |
Should the window still be "script closable"? (https://html.spec.whatwg.org/#script-closable) Should we unset the browsing context's name? |
Right, that was the next question I was about to ask. In Gecko, setting opener to null makes navigation targeting cross-origin impossible, but That's why we need tests and a clear idea of which spec sections are affected. |
https://html.spec.whatwg.org/#traverse-the-history step 4.2.2 branches on auxiliary browsing context without a corresponding check to the opener browsing context. I can't really figure out how that would have an effect. I guess another thing that would be worth clarifying here is how this relates to creator browsing contexts. Perhaps the origin still needs to be an alias and referrer still needs to be a copy. As for tests, I don't think we really have good multi-window testing infrastructure. @jgraham? |
So, the problem is that we |
One problem I think is that it may require a user gesture for the invocation to succeed. They could communicate with |
@jgraham: Part of the point of the change is to remove the explicit communication channels. :) As @annevk notes, there are probably side channels we could exploit for a same-origin window. I'm not sure how we'd approach it for a cross-origin window. @annevk: You're correct that (at least in Chrome) |
We should at least create some manual tests or something. I mean, we need some conformance tests here.. |
Manual tests is OK (when automated is not possible). One day manual tests in wpt can be automated with WebDriver. |
I tried to address some of the questions in #313 (comment). That also contains a few more demos. |
Progress on tests:
If the basic test is just illustrating a simple bug in Gecko it seems fairly easy to use that kind of framework to create multi-window tests as well. To ensure two windows have been opened with the same name rather than one that is being reused and such. |
ea8ebda
to
b6ab3a0
Compare
Cookies or storage events should work as long as the windows are same-origin. I'll take a look at the PR to see how it reacts in Chrome... I don't think we have a reasonable solution for cross-origin windows. That's somewhat intentional. :) I think manual tests are the right way to validate this behavior. Browsers can add more intrusive tests in a variety of ways to ensure that the behavior doesn't regress (e.g. https://codereview.chromium.org/1443663003), and the manual tests can verify that those "magical" tests are verifying the right things. |
Note that if we decide we really care about automating cross-origin stuff we could require that in the testing framework firing of some particular event causes the browser to take some particular action that allows (async) communication as needed. Or something. |
I created more tests:
It seems Given this I still think my proposed change here is correct. |
Chrome agrees with Firefox's behavior in this regard, and doesn't allow A to target C. See web-platform-tests/wpt#2363. |
I don't think we want the behavior that A can target B's nested browsing contexts, same-origin or cross-origin. That seems to be ripe for various kinds of phishing attacks, as it would allow folks to open up a page with named frames, and replace their contents arbitrarily. It looks like both Chrome and Firefox block this behavior, popping up a new window instead of allowing A to target C or D. |
You mean in the case when A and B are not same-origin? Seems to me like if A and B are same-origin and both toplevel and B is not disowned then A should be able to target at least B's immediate child browsing contexts. For what it's worth, here is the explicit algorithm that Gecko uses right now to decide whether A can target B for navigation (ignoring some complexity around
Now we're going to want to make changes to this stuff to deal with disowning well, obviously. Just wanted to get what we do written down. |
The Chrome algorithm is https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/frame/Frame.cpp&l=201 per @mikewest. @mikewest does not agree with a test in web-platform-tests/wpt#2356 which checks when A opens B that has a child C, that C can navigate A (with A, B, and C having different origins). The fact that C can navigate B to C' which can then navigate A was not convincing as that would be more noticeable to the user. Furthermore the fact that navigating B, especially cross-origin does not disown B, was also something @mikewest wanted to look into changing. |
Navigating B in what sense? If A opens B and then navigates it a bunch, it should continue to be able to do so, right? Pretty sure that's needed for web compat. If a user navigates B, things are more complicated, at least in terms of user expectations. |
I guess I'm having a hard time writing down a proposed specification even with the feedback you've already given. One thing that seems weird to me is that the specification has "familiar with" and "allowed to navigate", but it seems like implementations only have the latter? Here's a proposed rewrite of familiar with to take your feedback into account: A is familiar with B if one of these is true:
|
The spec's "allowed to navigate" algorithm is unrelated to link targeting. It's basically the algorithm that enforces the navigation-related sandboxing flags. So basically the "familiar with" algorithm determines which browsing context a target="foo" resolves to. Then "allowed to navigate" determines whether you can actually navigate it and only matters if you're sandboxed to start with. Browsers implement both of these algorithms, in some form.
Thank you for putting this together. I think these rules have at least the following possibly-undesirable implications:
In general, it seems that if we want disowning to have the semantics of "just put this in a new process" then if A opens B and B is disowned, targeting of B and things it loads-as-subframes/opens from should be prevented from A. Similarly, A and the things it loads-as-subframes or the things it opens or the things that opened it should not be targetable from B. But things B opens should be able to target B and be targeted by B, unless those things are themselves disowned, right? |
So thinking about this a bit more... What we perhaps really want for the noopener/noreferrer thing is to make the two browsing contexts involved (opener and opened thing) not "directly reachable" in the sense of https://html.spec.whatwg.org/#directly-reachable-browsing-contexts That will also make them not be in the same "unit of related browsing contexts", right? Note that the actual spec for targeting at https://html.spec.whatwg.org/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name says:
We could try to require that "related enough" include "in the same unit of related browsing contexts". This would match absolutely no one's current implementation, I'm pretty sure, but would be possible to converge on, probably. That still leaves the problem of what to do with dynamic sets of window.opener to null. We could try to require that those also cut the "directly reachable" link (in both directions) and hence change whether the two things are in the same "unit of related browsing contexts". Implementing this might be a bit more annoying, but is probably doable... Then, within a single unit of related browsing contexts, we can think about what the "familiar with" rules should be, but without having to worry about disowning anymore, since that's already handled. |
Okay, so we would make these changes instead:
|
Right, that's basically what I was thinking about. |
I have attempted to update the PR to take that into account. I also updated the commit message. |
@bzbarsky ping. |
source
Outdated
the new value is anything else then the user agent must | ||
object, on getting, must return the <code>WindowProxy</code> object of the current <span>browsing | ||
context</span>'s <span>opener browsing context</span>, if there is one and it is not | ||
<span>disowned</span>; otherwise, it must return null. On setting, if the new value is null then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem right. Just because the parent is disowned, doesn't mean that .opener
should return null.
Should this be checking whether the current browsing context is disowned instead?
So in general, we can have disowned things that can still reach each other with script references (e.g. A window.opens B, B sets opener to null, now B cannot reach A unless it stashed a ref somewhere, but A can reach B, perhaps not in the "reachable" sense of the spec, though). And as I said above, being disowned does not make one "no longer directly reachable". Just no longer directly reachable from the opener. Still directly reachable from its kids or things it opens, right? Does that make sense? |
This change attempts to make it so that when using rel=noopener, rel=noreferrer, and when setting window.opener to null, the browsing contexts involve can no longer directly reach each other. They end up in their own unit of related browsing contexts. (This is what some in the ECMAScript community refer to as a vat or continent.) We do this by making directly reachable account for disowning, by making familiar with account for directly reachable, and by changing the rules for choosing a browsing context given a browsing context name to no longer say "related enough", but instead clearly say that the browsing contexts have to be familiar with each other, and by extension, have to be directly reachable.
Sorry for following up so late. I'm feeling a little lost here, since I'm not super familiar with how all these things work and fit together. Since I noticed you are working on landing some stuff around this in Gecko I thought I'd give this PR another try. Will fix |
@@ -78152,37 +78155,54 @@ dictionary <dfn>DragEventInit</dfn> : <span>MouseEventInit</span> { | |||
the <span>browsing context</span> from which the <span>auxiliary browsing context</span> was | |||
created.</p> | |||
|
|||
<p>An <span>auxiliary browsing context</span> can be <dfn id="disowned-its-opener">disowned</dfn>. | |||
This means it is no longer <span data-x="directly reachable browsing contexts">directly | |||
reachable</span>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per your comments it seems this is flawed too. I'm not sure that leaves much in this PR other than cleanup. I think I lost track 😟
See whatwg/html#323 (comment) for context.
This feature has some outstanding issues and feature requests; see whatwg#323 and whatwg#1826. But this editorial cleanup creates a more solid foundation for future work.
The last couple of comments in #313 provide a way forward here. This is distraction at this point. |
Otherwise window names would still leak across.