Re: [whatwg] The choice of script global object to use when the script element is moved
On Wed, 2 Feb 2011, Henri Sivonen wrote: On Feb 2, 2011, at 03:07, Ian Hickson wrote: I suppose we could make it so that scripts get neutered when the document that they were first associated with gets unloaded. Would that work? We did something different. Proposal #1: Proposal #4 (what Gecko now does): * If at the time when the parser triggers the 'run' algorithm, the owner document of the script is not the same document whose active parser the parser is, set the 'already executed' flag and abort the steps. * If at the time of a script becoming available for evaluation the owner document of the script is not the same document that was the owner document at the time of the 'run' algorithm, don't evaluate the script. See https://bugzilla.mozilla.org/show_bug.cgi?id=592366 I believe this is what the spec now says (this was fixed in response to a bug that was filed, IIRC). Please let me know if it's still broken. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] The choice of script global object to use when the script element is moved
On Feb 2, 2011, at 03:07, Ian Hickson wrote: I suppose we could make it so that scripts get neutered when the document that they were first associated with gets unloaded. Would that work? We did something different. Proposal #1: Proposal #4 (what Gecko now does): * If at the time when the parser triggers the 'run' algorithm, the owner document of the script is not the same document whose active parser the parser is, set the 'already executed' flag and abort the steps. * If at the time of a script becoming available for evaluation the owner document of the script is not the same document that was the owner document at the time of the 'run' algorithm, don't evaluate the script. See https://bugzilla.mozilla.org/show_bug.cgi?id=592366 -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: [whatwg] The choice of script global object to use when the script element is moved
On Thu, 9 Sep 2010, Henri Sivonen wrote: On Sep 9, 2010, at 00:47, Ian Hickson wrote: On Fri, 3 Sep 2010, Henri Sivonen wrote: When evaluating a parser-inserted script, there are three potential script global objects to use: 1) The script global object of the document whose active parser the parser that inserted the script is. 2) The script global object of the document that owned the script element at the time of invoking the run algorithm. 3) The script global object of the document that owns the script element at the time of script evaluation. #1 and #2 are dodgy because the documents in question might have been GC'ed by that point. This problem doesn't arise in Gecko, because if a document gets GC'ed, the pending external script loads that have started while the script was in that document never get evaluated. That is, the document (via its script loader) owns the pending loads--not the script node. That's a problem in itself. It means you are exposing GC behaviour. I suppose we could make it so that scripts get neutered when the document that they were first associated with gets unloaded. Would that work? The spec says the answer is #3. WebKit (with HTML5 parser or without) says the answer is #1. Firefox 3.6 says the answer is #2. I doubt that there are Web compat considerations forcing this choice, because IE8 doesn't get as far as running the script in this case. IE9 tries to do either #2 or #3 (not sure which) succeeding for inline scripts and failing for external ones. (IIRC, the text in the spec that explains the distinction between 1 and the other (without explaining the distinction between 2 and 3) was added specifically for the benefit of the IE team.) I'm not sure exactly which sentence you mean here, but I'm happy to clarify text if anything is ambiguous. The example http://www.whatwg.org/specs/web-apps/current-work/#scripts-that-modify-the-page-as-it-is-being-parsed doesn't cover the script moving to a third document between the first parser-performed insertion and the external script finishing loading. I've added an example for this; I'll change it if we change the spec. One advantage of doing #3 is that, as Adam pointed out, the implementation is required to get the security context at the last minute, where it's most likely to be up to date (e.g. with document.domain changes, etc) even in the case of the script element not being moved around. For last-minute security context grabbing to have an extra benefit, wouldn't the security checks have to be re-performed at last-minute? I don't see why. The idea is to make sure that further origin checks are done with the latest information, to _enable_ further interactions; not to reduce the number of interactions. Doing the other checks later wouldn't enable anything new as far as I can tell. #3 is simpler to understand, IMHO. However, #1 is not particularly hard to spec, and I guess does decrease the odds of scripts being made to run accidentally by a bug in a script using sandboxed or CSP context. If everyone is ok with #1, I'm happy to change the spec accordingly. In case we don't end up doing #1, I have a follow-up question: Is there a good reason to perform the run algorithm against the then-current owner doc as opposed to the parser's doc for parser-inserted scripts? (Performing it against the parser's doc would require fewer changes to Gecko but implementing the checks against the owner doc would be doable.) If we don't end up doing #1, then the answer would be that doing anything against the parser's doc would be quite inconsistent. Suppose there are two docs from one Origin. The document that the parser is associated with doesn't have a CSP. A script in it moves a node in such a way that the parser ends up inserting subsequent scripts into another document. That document has a CSP that bans scripts. Would you consider it a bug if a script ran in the context of the script global object of the document whose CSP says no scripts? If the CSP applied then the script would not run, if it didn't then it would run in the context of the doc without the CSP. I'm sure we wouldn't want to define the CSP as applying to nodes in a different way than the global scope is picked. Currently, CSP is evaluated at the run algorithm time. This seems a natural extension to the scripting disabled check that happens at run algorithm time. I guess that makes sense. I don't really see a scenario in which a non-hostile script would insert possibly-untrusted scripts into another document _after_ they have been created and 'run', but _before_ they have been 'executed'. If the are inserted into the other doc _before_ they are 'run', you'd want the CSP to apply, and you'd want either #2 or #3 from the list above, though I am finding it hard to imagine a
Re: [whatwg] The choice of script global object to use when the script element is moved
On Sep 9, 2010, at 00:47, Ian Hickson wrote: On Fri, 3 Sep 2010, Henri Sivonen wrote: When evaluating a parser-inserted script, there are three potential script global objects to use: 1) The script global object of the document whose active parser the parser that inserted the script is. 2) The script global object of the document that owned the script element at the time of invoking the run algorithm. 3) The script global object of the document that owns the script element at the time of script evaluation. #1 and #2 are dodgy because the documents in question might have been GC'ed by that point. This problem doesn't arise in Gecko, because if a document gets GC'ed, the pending external script loads that have started while the script was in that document never get evaluated. That is, the document (via its script loader) owns the pending loads--not the script node. I could see theoretical merit in an argument that this is itself dodgy for script-inserted external scripts. However, I think the parser or the document whose active parser the parser is should own the loads for parser-inserted external script, because things become weird if defer script handling doesn't stay with the inserter parser and things get weird if the parser-blocking script doesn't stay with the inserter parser. While it would be *possible* to decouple various aspects of script loading from each other, I think it's not really worthwhile to go through that exercise just for an edge case that's currently broken in more severe ways in the current release versions every one of the top 4 engines. That is, I'd really like to see http://www.w3.org/Bugs/Public/show_bug.cgi?id=10540 and http://www.w3.org/Bugs/Public/show_bug.cgi?id=10542 become FIXED rather than WONTFIX. Furthermore (to avoid major changes to Gecko's script loading), I'd like the pending load of script-inserted external scripts to be owned by the owner doc at the time of the run algorithm. The spec says the answer is #3. WebKit (with HTML5 parser or without) says the answer is #1. Firefox 3.6 says the answer is #2. I doubt that there are Web compat considerations forcing this choice, because IE8 doesn't get as far as running the script in this case. IE9 tries to do either #2 or #3 (not sure which) succeeding for inline scripts and failing for external ones. (IIRC, the text in the spec that explains the distinction between 1 and the other (without explaining the distinction between 2 and 3) was added specifically for the benefit of the IE team.) I'm not sure exactly which sentence you mean here, but I'm happy to clarify text if anything is ambiguous. The example http://www.whatwg.org/specs/web-apps/current-work/#scripts-that-modify-the-page-as-it-is-being-parsed doesn't cover the script moving to a third document between the first parser-performed insertion and the external script finishing loading. So in conclusion, I really don't see a new attack vector regardless of what we do here. OK. One advantage of doing #3 is that, as Adam pointed out, the implementation is required to get the security context at the last minute, where it's most likely to be up to date (e.g. with document.domain changes, etc) even in the case of the script element not being moved around. For last-minute security context grabbing to have an extra benefit, wouldn't the security checks have to be re-performed at last-minute? #3 is simpler to understand, IMHO. However, #1 is not particularly hard to spec, and I guess does decrease the odds of scripts being made to run accidentally by a bug in a script using sandboxed or CSP context. If everyone is ok with #1, I'm happy to change the spec accordingly. In case we don't end up doing #1, I have a follow-up question: Is there a good reason to perform the run algorithm against the then-current owner doc as opposed to the parser's doc for parser-inserted scripts? (Performing it against the parser's doc would require fewer changes to Gecko but implementing the checks against the owner doc would be doable.) Suppose there are two docs from one Origin. The document that the parser is associated with doesn't have a CSP. A script in it moves a node in such a way that the parser ends up inserting subsequent scripts into another document. That document has a CSP that bans scripts. Would you consider it a bug if a script ran in the context of the script global object of the document whose CSP says no scripts? If the CSP applied then the script would not run, if it didn't then it would run in the context of the doc without the CSP. I'm sure we wouldn't want to define the CSP as applying to nodes in a different way than the global scope is picked. Currently, CSP is evaluated at the run algorithm time. This seems a natural extension to the scripting disabled check that happens at run algorithm time. -- Henri Sivonen hsivo...@iki.fi
Re: [whatwg] The choice of script global object to use when the script element is moved
On Tue, 07 Sep 2010 22:57:27 +0200, Adam Barth w...@adambarth.com wrote: It sounds like CSP is creating sub-origin privileges. Sub-origin privileges don't really work, so it's unclear to what a sensible result would be. This is a problem with your alternative CSP proposal as well, no? https://wiki.mozilla.org/Security/CSP/AllowedScripts It prevents a bunch of things, but when loaded in an iframe someone else on the same-origin can still inject a script of some sorts. -- Anne van Kesteren http://annevankesteren.nl/
Re: [whatwg] The choice of script global object to use when the script element is moved
On Wed, Sep 8, 2010 at 2:10 AM, Anne van Kesteren ann...@opera.com wrote: On Tue, 07 Sep 2010 22:57:27 +0200, Adam Barth w...@adambarth.com wrote: It sounds like CSP is creating sub-origin privileges. Sub-origin privileges don't really work, so it's unclear to what a sensible result would be. This is a problem with your alternative CSP proposal as well, no? https://wiki.mozilla.org/Security/CSP/AllowedScripts It prevents a bunch of things, but when loaded in an iframe someone else on the same-origin can still inject a script of some sorts. The goal of AllowedScripts is not to limit a privilege to a subset of an origin. Rather, the goal is to prevent an attacker who can inject markup into a document from executing script. Put another way, if you're already executing script, then it's not trying to withhold any privileges. Adam
Re: [whatwg] The choice of script global object to use when the script element is moved
On Wed, 08 Sep 2010 11:20:30 +0200, Adam Barth w...@adambarth.com wrote: The goal of AllowedScripts is not to limit a privilege to a subset of an origin. Rather, the goal is to prevent an attacker who can inject markup into a document from executing script. Put another way, if you're already executing script, then it's not trying to withhold any privileges. Fair enough. I guess if one page gets compromised all else that is same origin is lost anyway. -- Anne van Kesteren http://annevankesteren.nl/
Re: [whatwg] The choice of script global object to use when the script element is moved
On Wed, Sep 8, 2010 at 2:24 AM, Anne van Kesteren ann...@opera.com wrote: On Wed, 08 Sep 2010 11:20:30 +0200, Adam Barth w...@adambarth.com wrote: The goal of AllowedScripts is not to limit a privilege to a subset of an origin. Rather, the goal is to prevent an attacker who can inject markup into a document from executing script. Put another way, if you're already executing script, then it's not trying to withhold any privileges. Fair enough. I guess if one page gets compromised all else that is same origin is lost anyway. As I understand it, this is the general design thinking for CSP too. Additionally, the recommended best practices is to use the same CSP policies for all urls in a domain, which also avoids the discussed attack. / Jonas
Re: [whatwg] The choice of script global object to use when the script element is moved
On Fri, 3 Sep 2010, Henri Sivonen wrote: When evaluating a parser-inserted script, there are three potential script global objects to use: 1) The script global object of the document whose active parser the parser that inserted the script is. 2) The script global object of the document that owned the script element at the time of invoking the run algorithm. 3) The script global object of the document that owns the script element at the time of script evaluation. #1 and #2 are dodgy because the documents in question might have been GC'ed by that point. The spec says the answer is #3. WebKit (with HTML5 parser or without) says the answer is #1. Firefox 3.6 says the answer is #2. I doubt that there are Web compat considerations forcing this choice, because IE8 doesn't get as far as running the script in this case. IE9 tries to do either #2 or #3 (not sure which) succeeding for inline scripts and failing for external ones. (IIRC, the text in the spec that explains the distinction between 1 and the other (without explaining the distinction between 2 and 3) was added specifically for the benefit of the IE team.) I'm not sure exactly which sentence you mean here, but I'm happy to clarify text if anything is ambiguous. The spec asserts that these options are equally safe, because if something is able to move the scripts so that 1, 2 and 3 would result in different script global objects, the script gets moved within one Origin. There's some weirdness, e.g. if one of the browsing contexts has script disabled or if document.domain gets changed after the script node is moved to another document, but yeah, as far as I can tell either option is safe. However, if there's something other than Same Origin restricting what scripts are eligible for evaluation (e.g. Content Security Policies that I don't know well enough to reason about), 1, 2 and 3 might not be equally safe. Essentially, there are two browsing contexts, the one with the parser and the other one. - If the one with the parser moves the script to the other context: for an attack to be relevant here, the script would have to run in the other context, but any attack possible this way could also be done by just creating a script in that document and appending it, or setting onload or onclick or some such content attribute in that document. If script is disabled in that other browsing context then nothing happens. - If the one without the parser grabs the script and inserts it into itself, then for any attack to be interesting, scripting in the parser doc has to be disabled (since otherwise the other doc could just inject script into the parser doc and do whatever it wanted as if it was itself the parser doc). If we make scripts run in the parser doc context, then you can use this to grab a script src= that is Referer-checked and execute it in the other doc's context, grabbing any information from that script. However, you could also do this by just pushState()ing to the other doc's URL, and then obtaining the script directly. The other possibility is scripts running in the non-parser doc context, but as far as I can tell you can always just grab the script from the other DOM and copy it to run in the non-parser doc, so again no new security problem seems to be introduced. So in conclusion, I really don't see a new attack vector regardless of what we do here. * Why does the spec say #3 when none of the browsers did #3 at the time of spec writing? I don't know the original reason. I would guess it was simply a matter of doing the simplest thing in the spec -- I try wherever possible to not refer back to the active parser if I can avoid it, letting things work identically with DOM manipulation from script as from the parser. Also, it avoids any weirdness like how to handle the case of the original doc(s) being GCed. * Are there use cases that favor any one of these in particular? (I doubt it.) They seem identical. FWIW, my gut says we should do #1, since it is obviously secure, except it would be unfortunate if the spec changed to #1 but too late for IE9 to match. They all seem obviously secure. If you can manipulate a document's DOM, you can essentially do anything including running arbitrary script in that document or run script from that document in your document. One advantage of doing #3 is that, as Adam pointed out, the implementation is required to get the security context at the last minute, where it's most likely to be up to date (e.g. with document.domain changes, etc) even in the case of the script element not being moved around. On Fri, 3 Sep 2010, Boris Zbarsky wrote: Could it cause script to run from a script element that someone sticks in a same-origin but sandboxed iframe if the non-sandboxed parent moves some part of the DOM out before the parse is done? The only relevant case would be a sandboxed frame that is marked
Re: [whatwg] The choice of script global object to use when the script element is moved
NOTE! This email contains URLs to pages that crash WebKit on reload, so you probably shouldn't follow the URLs here in any WebKit-based browser where you have something important going on in the same renderer process. (In Chrome, only the isolated content process crashes.) On Fri, Sep 3, 2010 at 3:49 AM, Henri Sivonen hsivo...@iki.fi wrote: When evaluating a parser-inserted script, there are three potential script global objects to use: 1) The script global object of the document whose active parser the parser that inserted the script is. 2) The script global object of the document that owned the script element at the time of invoking the run algorithm. 3) The script global object of the document that owns the script element at the time of script evaluation. The spec says the answer is #3. WebKit (with HTML5 parser or without) says the answer is #1. Firefox 3.6 says the answer is #2. On Sep 3, 2010, at 20:47, Adam Barth wrote: I'm not sure it makes much of a difference from a security point of view. I suspect WebKit does #3 because it grabs the security context immediately before executing the script. With my demos, WebKit seems to be doing #1: http://hsivonen.iki.fi/test/moz/move-during-parse-parent.html http://hsivonen.iki.fi/test/moz/move-during-parse-parent2.html The second one doesn't finish loading in Gecko (both with new and old parser), because Gecko tries to unblock the parser on the wrong document and never unblock the parser that needs to be unblocked. That actually seems marginally safer because it means you're unlikely to grab an out-dated security context. Since the check If scripting is disabled for the script element, or if the user agent does not support the scripting language given by the script block's type for this script element, then the user agent must abort these steps at this point. The script is not executed. happens at the time of the run algorithm and since iframe sandboxing or Content Security Policies can cause scripting to be disabled, a security check has to happen at the time of invoking the run algorithm (assuming we don't want to change the pre-existing behavior of what happens in the common same-document case where a script gets rejected and we don't want to decouple the time on supported language check from the time of security-based rejections; this would be detectable in the document.write() case). For external scripts, this means that if we want to evaluate against a script global object associated with the owner doc of the script node at evaluating time, the security checks may have been performed in the context of another document and script global object. If we want security checks against the script global object associated with the owner doc at evaluation time, I think it's necessary to do the security checks twice: one during the run algorithm (in which case failing the checks doesn't fire any error events) and another time right before evaluation (in which case I suppose a failure should act the same way as a network failure and fire the error event). That's more complex than what's in Gecko now. (Not insurmountably complex, but more complex anyway.) I'm worried about doing the security checks at run algorithm time and evaluating with a different script global object without redoing the security check. However, it may be that I only worry because I feel I don't know enough of all the possibilities to be confident that such a separation of time of check and time of use would be safe here. Is there any good reason (other than differing from current IE9 PP behavior) not to do #1 with the additional stipulation that making the document whose active parser the parser is go away makes the scripts that are pending to run in the context of its script global object behave (stop?) the same regardless of which document they are in? (I.e. if the document that had the active parser gets torn down before the scripts inserted into another doc have loaded, those scripts wouldn't be evaluated.) I still believe doing #1 in Gecko would be the simplest thing. With the test cases above, WebKit seems to be doing #1 already (and then crashing) and Opera fails to move the scripts so the execution context ends up being the same as it would in case #1. On Sep 3, 2010, at 20:55, Jonas Sicking wrote: On Fri, Sep 3, 2010 at 10:47 AM, Adam Barth w...@adambarth.com wrote: I'm not sure it makes much of a difference from a security point of view. Agreed. Pages can only move elements between pages that are in the same security context anyway so I can't really think of any attacks that any of the approaches would enable or disable. Suppose there are two docs from one Origin. The document that the parser is associated with doesn't have a CSP. A script in it moves a node in such a way that the parser ends up inserting subsequent scripts into another document. That document has a CSP that bans scripts.
Re: [whatwg] The choice of script global object to use when the script element is moved
On Tue, Sep 7, 2010 at 1:40 AM, Henri Sivonen hsivo...@iki.fi wrote: On Sep 3, 2010, at 20:55, Jonas Sicking wrote: On Fri, Sep 3, 2010 at 10:47 AM, Adam Barth w...@adambarth.com wrote: I'm not sure it makes much of a difference from a security point of view. Agreed. Pages can only move elements between pages that are in the same security context anyway so I can't really think of any attacks that any of the approaches would enable or disable. Suppose there are two docs from one Origin. The document that the parser is associated with doesn't have a CSP. A script in it moves a node in such a way that the parser ends up inserting subsequent scripts into another document. That document has a CSP that bans scripts. Would you consider it a bug if a script ran in the context of the script global object of the document whose CSP says no scripts? It sounds like CSP is creating sub-origin privileges. Sub-origin privileges don't really work, so it's unclear to what a sensible result would be. Adam
Re: [whatwg] The choice of script global object to use when the script element is moved
I'm not sure it makes much of a difference from a security point of view. I suspect WebKit does #3 because it grabs the security context immediately before executing the script. That actually seems marginally safer because it means you're unlikely to grab an out-dated security context. Adam On Fri, Sep 3, 2010 at 3:49 AM, Henri Sivonen hsivo...@iki.fi wrote: When evaluating a parser-inserted script, there are three potential script global objects to use: 1) The script global object of the document whose active parser the parser that inserted the script is. 2) The script global object of the document that owned the script element at the time of invoking the run algorithm. 3) The script global object of the document that owns the script element at the time of script evaluation. The spec says the answer is #3. WebKit (with HTML5 parser or without) says the answer is #1. Firefox 3.6 says the answer is #2. I doubt that there are Web compat considerations forcing this choice, because IE8 doesn't get as far as running the script in this case. IE9 tries to do either #2 or #3 (not sure which) succeeding for inline scripts and failing for external ones. (IIRC, the text in the spec that explains the distinction between 1 and the other (without explaining the distinction between 2 and 3) was added specifically for the benefit of the IE team.) The spec asserts that these options are equally safe, because if something is able to move the scripts so that 1, 2 and 3 would result in different script global objects, the script gets moved within one Origin. However, if there's something other than Same Origin restricting what scripts are eligible for evaluation (e.g. Content Security Policies that I don't know well enough to reason about), 1, 2 and 3 might not be equally safe. Questions: * Is anyone aware of an existing or upcoming security mechanism that would not make the three above cases equally safe--especially if e.g. the security check was made according to #1 but the effective script global object were chosen accoding to #3? * Why does the spec say #3 when none of the browsers did #3 at the time of spec writing? * Are there use cases that favor any one of these in particular? (I doubt it.) FWIW, my gut says we should do #1, since it is obviously secure, except it would be unfortunate if the spec changed to #1 but too late for IE9 to match. -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: [whatwg] The choice of script global object to use when the script element is moved
On Fri, Sep 3, 2010 at 10:47 AM, Adam Barth w...@adambarth.com wrote: I'm not sure it makes much of a difference from a security point of view. Agreed. Pages can only move elements between pages that are in the same security context anyway so I can't really think of any attacks that any of the approaches would enable or disable. / Jonas
Re: [whatwg] The choice of script global object to use when the script element is moved
On 9/3/10 1:55 PM, Jonas Sicking wrote: On Fri, Sep 3, 2010 at 10:47 AM, Adam Barthw...@adambarth.com wrote: I'm not sure it makes much of a difference from a security point of view. Agreed. Pages can only move elements between pages that are in the same security context anyway so I can't really think of any attacks that any of the approaches would enable or disable. Could it cause script to run from a script element that someone sticks in a same-origin but sandboxed iframe if the non-sandboxed parent moves some part of the DOM out before the parse is done? -Boris