- From: Justin Lebar <justin.lebar@gmail.com>
- Date: Sun, 16 Sep 2012 22:14:52 -0400
- To: WHAT Working Group <whatwg@whatwg.org>
- Cc: Boris Zbarsky <bzbarsky@mit.edu>
It's time for another episode of everyone's favorite show: "Find the session history spec bug". Today's episode is a double-header of related issues. == Issue #1 == Suppose an attack page evil.html controls a separate frame F (e.g. evil.html frames F, evil.html opened F as a popup window, or vice versa). We discovered that if evil.html causes F to 1. load a.html 2. start loading b.html 3. load a.html#h then step (3) cannot cancel the load of b.html. That is, the final session history from this sequence must be either a.html <-- oldest a.html#h b.html <-- current or a.html <-- oldest b.html <-- current. All browsers I tested gave one of the above two results. Doing anything else breaks the web (we shipped this in Firefox Nightly and people were unable to log into ingdirect.com, for example). I didn't investigate too thoroughly, but I believe what happens is, some sites use a link with href "#" and then navigate themselves in the link's onclick handler, without cancelling the click event. In that case, we do precisely steps 1-3 above. As I read the spec, browsers are supposed to cancel the load of b.html in step 3 above. In the navigation algorithm [1], step 6 explicitly cancels the load of b.html, because the load of b.html has not matured. So if I understand correctly, the spec is dictating behavior that we know won't work and that no browser implements. The presence of steps 6 and 8 in the algorithm suggest that the spec is already trying to walk this line, so maybe I misunderstand what's going on, either in my tests or in the spec. == Issue #2 == Suppose again that evil.com controls a frame F, and evil.com causes F to 1. load a.html 2. load a.html#h 3. start loading b.html 4. go back When we go back, we traverse the history [2] from a.html#h to a.html. Per the spec, this doesn't cancel the load of b.html. This caused a problem for us in Firefox because we create a session history entry for b.html at the beginning of step 3 and insert it after the current one. Then, when the load of b.html completes, we use whichever session history entry happens to be after the current one, assuming that it was the session history entry we created earlier. In this case, our assumption is wrong, and we load b.html into a.html#h's session history entry. This is somewhat disastrous, but I'd prefer not to elaborate further until we've shipped a fix for this issue in all supported versions of Firefox. The fix for this bug is not as simple as merely ensuring that the session history entry's URL matches the document's URL. Due to hash navigations and pushstate, these URLs may not match even when we're behaving correctly. We fixed this bug by cancelling the load of b.html when you go back. This matches Chrome's behavior in my tests [3]. Notice that this means we're cancelling an outstanding network load due to a synchronous same-document load, which I said in part 1 breaks the web. But based on the (lack of) feedback we've received from our test audience, it seems that cancelling the load of b.html does /not/ break the web if the navigation from a.html to a.html#h is a history navigation. The right thing to do is probably to load b.html after a.html, so the final session history is a.html <-- oldest b.html <-- current. I /think/ this is what the spec says should happen, but I'm not sure. But matching the spec here would be difficult in our current architecture, and anyway wouldn't match the one other browser I was able to test, so perhaps a spec should be changed to match. Regards, -Justin [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#navigating-across-documents [2] http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#history-traversal [3] I wasn't able to test Opera or IE because my testcase was cross-origin and other browsers forbid cross-origin back/forward. The testcase uses the fact that it's cross-origin to get the right timing, so it's actually not clear to me how to test this behavior in other browsers.
Received on Monday, 17 September 2012 02:15:41 UTC