Re: [whatwg] Navigation and history traversal issues

2013-09-25 Thread Ian Hickson
On Thu, 22 Aug 2013, Andrew Oakley wrote:
 On 19/09/12 01:18, Ian Hickson wrote:
 
  I've changed the spec so that traversing the history by a delta always 
  cancels any pending navigations unless you're in the middle of an 
  unload, in which case it just aborts the algorithm entirely.
  
  I've also made back()/forward()/go() not work during the document's 
  unload handler, since that could be used for griefing. I'm tempted to 
  disable it entirely for all docs a la alert(), but I've no idea if 
  that's Web- compatible and I suspect not.
 
 I assume this is where steps 3 and 4 of the traverse the history by a 
 delta algorithm came from.

Step 3. Step 4 is about canceling an existing navigation if you hit back.


 It's not clear from the spec which browsing context and document these 
 steps refer to.  Is it the specified browsing context and the active 
 document of that context (I think that makes most sense)?

Hm. I meant it to be the Document of the History object, but you raise an 
interesting point. This whole thing is rather poorly defined.

I've tried to clear it up.


 Additionally it isn't clear which event loop the task should be 
 associated with.

I've tried to clear this up too. It turns out this wasn't taking into 
account per-frame process isolation, anyway. I had to introduce yet 
another kind of event loop. This does introduce some race conditions in 
UAs with more than one event loop per tab, but I don't know what we can do 
about that without adding in a lot of blocking during traversal, which I 
am guessing wouldn't be popular.


  Aah, ok. The spec already says that's not allowed. You can't get to 
  the History object of a cross-origin Window:
  
  http://www.whatwg.org/specs/web-apps/current-work/#security-window
  
  (I forget what the story is if you get a History object from a 
  same-origin Window, then have the browsing context navigated, then use 
  the History object you kept around... I expect it is supposed to work 
  much as if you were to call it on the new, cross-origin, History 
  object, though.)
 
 The implication here as that you should never be able to do a history 
 traversal of a browsing context that is not same origin (and so there is 
 only one event loop to choose from).  The story about keeping history 
 objects around seems does not seem to be specified anywhere (so the 
 assumption was that it should work as normal).

 It looks like some browsers don't let you use history objects you kept 
 around (they should probably throw an InvalidStateError), others let you 
 use them if the current document of the relevant browsing context is 
 same-origin (and should probably throw a SecurityError).
 
 It's rather awkward to test this, but can we have something in the spec 
 to prevent cross-origin history traversal?  If this is not in the same 
 section as the traverse the history by a delta algorithm can we have a 
 note to say that this can never happen cross-origin?

Well, no, not really, because it can. For example, if you have an iframe 
that's cross-origin, and it's navigated, and then you call your own 
History object's back() method, it'll actually traverse that iframe.

But a History object of a non-active Document is a different matter...

Looks like this will need help from WebIDL. I've filed bug 23359 and 
marked it as blocked on bug 23358:

   https://www.w3.org/Bugs/Public/show_bug.cgi?id=23359
   https://www.w3.org/Bugs/Public/show_bug.cgi?id=23358

-- 
Ian Hickson   U+1047E)\._.,--,'``.fL
http://ln.hixie.ch/   U+263A/,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'


Re: [whatwg] Navigation and history traversal issues

2013-08-22 Thread Andrew Oakley
On 19/09/12 01:18, Ian Hickson wrote:
 I've changed the spec so that traversing the history by a delta
 always cancels any pending navigations unless you're in the middle of
 an unload, in which case it just aborts the algorithm entirely.
 
 I've also made back()/forward()/go() not work during the document's
 unload handler, since that could be used for griefing. I'm tempted to
 disable it entirely for all docs a la alert(), but I've no idea if
 that's Web- compatible and I suspect not.

I assume this is where steps 3 and 4 of the traverse the history by a
delta algorithm came from.

It's not clear from the spec which browsing context and document these
steps refer to.  Is it the specified browsing context and the active
document of that context (I think that makes most sense)?

Additionally it isn't clear which event loop the task should be
associated with.

 Aah, ok. The spec already says that's not allowed. You can't get to
 the History object of a cross-origin Window:
 
 http://www.whatwg.org/specs/web-apps/current-work/#security-window
 
 (I forget what the story is if you get a History object from a
 same-origin Window, then have the browsing context navigated, then
 use the History object you kept around... I expect it is supposed to
 work much as if you were to call it on the new, cross-origin, History
 object, though.)

The implication here as that you should never be able to do a history
traversal of a browsing context that is not same origin (and so there is
only one event loop to choose from).  The story about keeping history
objects around seems does not seem to be specified anywhere (so the
assumption was that it should work as normal).

It looks like some browsers don't let you use history objects you kept
around (they should probably throw an InvalidStateError), others let you
use them if the current document of the relevant browsing context is
same-origin (and should probably throw a SecurityError).

It's rather awkward to test this, but can we have something in the spec
to prevent cross-origin history traversal?  If this is not in the same
section as the traverse the history by a delta algorithm can we have a
note to say that this can never happen cross-origin?

Thanks

-- 
Andrew Oakley


[whatwg] Navigation and history traversal issues

2012-09-18 Thread Ian Hickson
On Tue, 12 Jun 2012, James Graham wrote:

 In particular, what stops such navigations from re-triggering the unload 
 handler, and thus starting yet another navigation?

I've updated the spec to have guards in place for 'pagehide' and 'unload'.

(Not yet 'beforeunload'. Should we do that too?)


 It looks like the spec tries to make a distinction between navigations 
 that are cross-origin and those that are not (step 4 in the navigating 
 across documents algorithm); I'm not sure why this inconsistency is 
 desirable rather than using the cross-origin approach always.
 
 Based on some tests ([1]-[5]), it seems that WebKit seems to cancel the 
 navigation in the unload handler always, Opera seems to always carry out 
 the navigation in the unload handler, and Gecko seems to follow WebKit 
 in the cross-origin case and Opera in the same-origin case. In all cases 
 the unload handler is only called once.
 
 [1] http://hoppipolla.co.uk/tests/navigation/003.html
 [2] http://hoppipolla.co.uk/tests/navigation/004.html
 [3] http://hoppipolla.co.uk/tests/navigation/005.html
 [4] http://hoppipolla.co.uk/tests/navigation/006.html
 [5] http://hoppipolla.co.uk/tests/navigation/007.html

On Tue, 12 Jun 2012, Boris Zbarsky wrote:
 
 For what it's worth, we initially tried to do what you say WebKit does 
 but ran into web compat issues.  See 
 https://bugzilla.mozilla.org/show_bug.cgi?id=371360 for the original bug 
 where we blocked all navigation during unload and 
 https://bugzilla.mozilla.org/show_bug.cgi?id=409888 for the bug where we 
 changed to the current behavior.  I believe the spec says what it says 
 based on our implementation experience here...

Yeah, the spec's behaviour is intentional here. The error in the spec was 
just that it still fired unload again. I've fixed that.


On Wed, 13 Jun 2012, James Graham wrote:
 
 That seems to be true. On the other hand it appears that gecko will 
 still respect navigation from unload even if the unload was triggered by 
 explicit user interaction (e.g. by editing the address bar), as long as 
 all the origins match, so you can end up at a different page to the one 
 you expected. That is very surprising behaviour (although I see that you 
 can argue that it is possible in other ways).

When it's same origin, you really have no way to know what's going on. The 
page could trivially pushState() a continuously changing URL, for example, 
and could serve random files from the server for any URL.


On Thu, 14 Jun 2012, James Graham wrote:
 On 06/13/2012 11:18 PM, Ian Hickson wrote:
  On Fri, 20 Apr 2012, Henri Sivonen wrote:

* Should window.stop() really not abort the parser like the spec 
seems to suggest?
   
   Looks like Opera is alone with the non-aborting behavior. The spec 
   is wrong.
  
  Can you elaborate on this? How can you tell?
 
 I presume the TC is something like
 
 !doctype html
 Before stop
 script
 window.stop()
 /script
 After stop
 
 Only Opera displays after stop here. We are planning to change this 
 behaviour, so that window.stop is much more like the abort the 
 document (I haven't yet closely studied how this interacts with the 
 readystate and other things that Henri has been looking at).

The spec now clearly requires the parser-stopping behaviour.

See also this bug where I'm tracking an issue with the word cancel:
   https://www.w3.org/Bugs/Public/show_bug.cgi?id=16801


On Fri, 15 Jun 2012, James Graham wrote:
 
 FWIW I think the conceptually simplest solution here is for aborting the 
 document to go through The End, so that defer scripts are run, 
 DOMContentLoaded and load events fire, and the readyState changes in the 
 normal way. This isn't quite like the behaviour of Gecko or WebKit 
 today, but is spec-wise easy to understand, and hopefully no one is 
 relying too much on specific behaviour of window.stop().

Aborting a document happens for many reasons other than stop(). For 
example, document.open(), navigation, the user hitting STOP, going 
back() in history, etc. In particular, The End can block on network, so 
we definitely don't want to require that UAs do that when you close a tab, 
for example.


On Wed, 15 Aug 2012, Glenn Maynard wrote:

 Should this alert on initial load?
 
 !doctype htmlbody onpopstate=alert('xxx')
 
 [1] says After creating the Document object, but before any script 
 execution, certainly before the parser stops, the user agent must update 
 the session history with the new page.  That invokes [2] update the 
 session history with the new page, which invokes [3] Traverse the 
 history to the new entry, which fires popstate in step 14.
 
 However, After creating the Document object, but before any script 
 execution seems like it could happen before or after the body element 
 has been parsed, so the alert may or may not happen.

Yeah, this is an oversight as specced. Fixed.


On Sun, 16 Sep 2012, Justin Lebar wrote:

 Suppose an attack page evil.html controls a separate frame F (e.g. 
 

Re: [whatwg] Navigation and history traversal issues

2012-09-18 Thread Justin Lebar
This is all great; thanks for the quick turnaround!

 I've also made back()/forward()/go() not work during the document's unload
 handler, since that could be used for griefing. I'm tempted to disable it
 entirely for all docs a la alert(), but I've no idea if that's Web-
 compatible and I suspect not.

I don't know what you mean by the last sentence here.  In my tests, IE
and Opera do not support cross-origin back/forward/go, if that's what
you mean.  I don't see any good reason for us to support that in
Firefox, either, if we could get away with removing it.

-Justin

On Tue, Sep 18, 2012 at 8:18 PM, Ian Hickson i...@hixie.ch wrote:
 On Tue, 12 Jun 2012, James Graham wrote:

 In particular, what stops such navigations from re-triggering the unload
 handler, and thus starting yet another navigation?

 I've updated the spec to have guards in place for 'pagehide' and 'unload'.

 (Not yet 'beforeunload'. Should we do that too?)


 It looks like the spec tries to make a distinction between navigations
 that are cross-origin and those that are not (step 4 in the navigating
 across documents algorithm); I'm not sure why this inconsistency is
 desirable rather than using the cross-origin approach always.

 Based on some tests ([1]-[5]), it seems that WebKit seems to cancel the
 navigation in the unload handler always, Opera seems to always carry out
 the navigation in the unload handler, and Gecko seems to follow WebKit
 in the cross-origin case and Opera in the same-origin case. In all cases
 the unload handler is only called once.

 [1] http://hoppipolla.co.uk/tests/navigation/003.html
 [2] http://hoppipolla.co.uk/tests/navigation/004.html
 [3] http://hoppipolla.co.uk/tests/navigation/005.html
 [4] http://hoppipolla.co.uk/tests/navigation/006.html
 [5] http://hoppipolla.co.uk/tests/navigation/007.html

 On Tue, 12 Jun 2012, Boris Zbarsky wrote:

 For what it's worth, we initially tried to do what you say WebKit does
 but ran into web compat issues.  See
 https://bugzilla.mozilla.org/show_bug.cgi?id=371360 for the original bug
 where we blocked all navigation during unload and
 https://bugzilla.mozilla.org/show_bug.cgi?id=409888 for the bug where we
 changed to the current behavior.  I believe the spec says what it says
 based on our implementation experience here...

 Yeah, the spec's behaviour is intentional here. The error in the spec was
 just that it still fired unload again. I've fixed that.


 On Wed, 13 Jun 2012, James Graham wrote:

 That seems to be true. On the other hand it appears that gecko will
 still respect navigation from unload even if the unload was triggered by
 explicit user interaction (e.g. by editing the address bar), as long as
 all the origins match, so you can end up at a different page to the one
 you expected. That is very surprising behaviour (although I see that you
 can argue that it is possible in other ways).

 When it's same origin, you really have no way to know what's going on. The
 page could trivially pushState() a continuously changing URL, for example,
 and could serve random files from the server for any URL.


 On Thu, 14 Jun 2012, James Graham wrote:
 On 06/13/2012 11:18 PM, Ian Hickson wrote:
  On Fri, 20 Apr 2012, Henri Sivonen wrote:
   
* Should window.stop() really not abort the parser like the spec
seems to suggest?
  
   Looks like Opera is alone with the non-aborting behavior. The spec
   is wrong.
 
  Can you elaborate on this? How can you tell?

 I presume the TC is something like

 !doctype html
 Before stop
 script
 window.stop()
 /script
 After stop

 Only Opera displays after stop here. We are planning to change this
 behaviour, so that window.stop is much more like the abort the
 document (I haven't yet closely studied how this interacts with the
 readystate and other things that Henri has been looking at).

 The spec now clearly requires the parser-stopping behaviour.

 See also this bug where I'm tracking an issue with the word cancel:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=16801


 On Fri, 15 Jun 2012, James Graham wrote:

 FWIW I think the conceptually simplest solution here is for aborting the
 document to go through The End, so that defer scripts are run,
 DOMContentLoaded and load events fire, and the readyState changes in the
 normal way. This isn't quite like the behaviour of Gecko or WebKit
 today, but is spec-wise easy to understand, and hopefully no one is
 relying too much on specific behaviour of window.stop().

 Aborting a document happens for many reasons other than stop(). For
 example, document.open(), navigation, the user hitting STOP, going
 back() in history, etc. In particular, The End can block on network, so
 we definitely don't want to require that UAs do that when you close a tab,
 for example.


 On Wed, 15 Aug 2012, Glenn Maynard wrote:

 Should this alert on initial load?

 !doctype htmlbody onpopstate=alert('xxx')

 [1] says After creating the Document object, but before any script
 execution, 

Re: [whatwg] Navigation and history traversal issues

2012-09-18 Thread Ian Hickson
On Tue, 18 Sep 2012, Justin Lebar wrote:

 This is all great; thanks for the quick turnaround!
 
  I've also made back()/forward()/go() not work during the document's 
  unload handler, since that could be used for griefing. I'm tempted to 
  disable it entirely for all docs a la alert(), but I've no idea if 
  that's Web- compatible and I suspect not.
 
 I don't know what you mean by the last sentence here.  In my tests, IE 
 and Opera do not support cross-origin back/forward/go, if that's what 
 you mean.  I don't see any good reason for us to support that in 
 Firefox, either, if we could get away with removing it.

I meant blocking all scripted back/forward session history traversal while 
any page is running the unload algorithms.

As far as cross-origin back/forward, there are 404 pages on the Web that 
have javascript:history.back() links; these would break for cross-origin 
links if we blocked cross-origin history traversal. I don't really see 
much point. What's the security risk?

-- 
Ian Hickson   U+1047E)\._.,--,'``.fL
http://ln.hixie.ch/   U+263A/,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'


Re: [whatwg] Navigation and history traversal issues

2012-09-18 Thread Justin Lebar
  I've also made back()/forward()/go() not work during the document's
  unload handler, since that could be used for griefing. I'm tempted to
  disable it entirely for all docs a la alert(), but I've no idea if
  that's Web- compatible and I suspect not.

 I don't know what you mean by the last sentence here.  In my tests, IE
 and Opera do not support cross-origin back/forward/go, if that's what
 you mean.  I don't see any good reason for us to support that in
 Firefox, either, if we could get away with removing it.

 I meant blocking all scripted back/forward session history traversal while
 any page is running the unload algorithms.

Ah, I see.  I don't have any idea if that's a good idea or not, so, okay.  :)

 As far as cross-origin back/forward, there are 404 pages on the Web that
 have javascript:history.back() links; these would break for cross-origin
 links if we blocked cross-origin history traversal. I don't really see
 much point. What's the security risk?

The issue isn't a history.back() which crosses origins -- that seems
fine -- but rather calling history.back() on a cross-origin window.
(Sorry that wasn't clear.)

It's not clear that this poses a security risk (otherwise, I'm sure
we'd have removed it by now), aside from making it easier to tickle
Firefox into buggy states like this bug [1].  But it's also not clear
to me what benefit there is to being able to call back() on an
arbitrary window.

I guess I can navigate a window, so I might as well be able to make it
go back?  But those aren't quite the same thing.

-Justin

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=737307


Re: [whatwg] Navigation and history traversal issues

2012-09-18 Thread Ian Hickson
On Tue, 18 Sep 2012, Justin Lebar wrote:
 
 The issue isn't a history.back() which crosses origins -- that seems 
 fine -- but rather calling history.back() on a cross-origin window. 
 (Sorry that wasn't clear.)

Aah, ok. The spec already says that's not allowed. You can't get to the 
History object of a cross-origin Window:

   http://www.whatwg.org/specs/web-apps/current-work/#security-window

(I forget what the story is if you get a History object from a same-origin 
Window, then have the browsing context navigated, then use the History 
object you kept around... I expect it is supposed to work much as if you 
were to call it on the new, cross-origin, History object, though.)

-- 
Ian Hickson   U+1047E)\._.,--,'``.fL
http://ln.hixie.ch/   U+263A/,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'