The global object in browsers
brendan at mozilla.com
Mon Jul 6 14:35:36 PDT 2009
Picking up this older thread, I owed you and others in TC39 a reply
from two face-to-face meetings ago.
On Feb 18, 2009, at 3:57 AM, Brendan Eich wrote:
> On Feb 17, 2009, at 11:18 PM, Mark Miller wrote:
>> You misunderstood me a bit, but no matter.
> Sorry, I couldn't see how to interpret your proposal otherwise. Let
> me know what I missed if you like.
> Maciej's right, the object identities practically dictate split
> windows. I suppose the original DOM level 0 could have made the
> split explicit, but it was not implemented this way at all back in
> the day. Different browser implementors solved the security and
> performance problems in similar ways, to preserve the view of the
> persistent window container as the one true "window object", really
> a proxy with multiple global objects hidden within it.
The issue we were debating in the TC39 meeting in March at Yahoo! was
whether |this|, window, self, and any other synonyms should bind to
the inner or outer window object.
Recall that split windows arise because the outer window is the
persistent object reference returned by window.open, frames[n],
document.getElementById(frameId), etc. that perdures across document
loads into that window or frame. The inner window is the ECMA-262
global object, a capability through which unmediated access to
sensitive variables including much of the DOM happens.
The inner window is thus the final object on the scope chain of all
objects created for a particular page, whether induced by markup or
created by DOM API calls. The outer window is a proxy that monitors
accesses and forwards them to the current inner window, or denies them.
During the evolution of split windows in Mozilla's codebase, we
observed that it's frightfully easy to leak the inner-window
capability if it is allowed to escape to script. So we made |this|,
window, and self bind to the outer window.
We even made our __parent__ extension, the read-only and undeletable
property reifying the intrinsic scope chain link in SpiderMonkey,
return the outer window, not the inner window that is the last object
on the scope chain of objects subordinate to that inner window, e.g.,
the current document, where document.__parent__ would seemingly
reference the inner window containing document.
Instead, we "outerize" inner window references as they try to escape
to user-level JS. Only privileged API can get the capability, and of
course it's baked in as the lexical scope chain link by the JS
compiler for top-level functions and variously optimized closures.
If the outer window sees that the "outerized" access is from the same
origin as the *current* inner window, it allows access. This is
expensive, or at least it has been until recently. With tracing and
polymorphic inline caching and the like, it's no longer too expensive
to consider imposing on all accesses.
(Maciej and I debated this with David-Sarah Hopwood for function
calls, and the jury's still out; more on this later, but see the paper
cited below for some encouraging results. But this is only one of the
reasons for split windows, so even if we did check access always, we
wouldn't give up split windows.)
The DOM does not use a capability model, rather it monitors certain
references to implement access control policies, again because
monitoring all references is too costly (or was in the nineties); also
access control was still the rage back when JS and Java were co-
evolving their security models. These access control judgments depend
on the baked-in and unforgeable intrinsic scope chain link, in order
to find the principals for subject script and target object. But the
DOM checks only some accesses, not all -- and in particular not access
to JS variables.
Here's the paper I mentioned at the last face-to-face but forgot to
follow up on (perhaps you've seen it already): http://www.adambarth.com/papers/2009/barth-weinberger-song.pdf
-- a nice paper on the problem of mixing capability with access-
control models -- old news to you I'm sure in its general results, but
perhaps novel in the split window and DOM vs. JS browser conflict.
Section 4.2 in the paper talks about a split window bug, or possibly
the lack of split windows altogether -- I *think*; I haven't looked
closely at the WebKit code in question. 4.3 describes a bug that is
very familiar to Mozilla JS hackers; nothing against WebKit here,
we're all in the same boat.
The paper's conclusion that defense in depth requires universal access
control checks at the JS level may not sit well with obj-cap fans, but
it fits the threat-space we've been facing all these years. Blame the
DOM, try to reform it or rewrite it (Caja, ADSafe) to use capabilities
instead of ids and names and too many references, but in the short run
the right fix for browser vendors dealing with the web-as-it-is looks
to me like this:
Convolve security labels with polymorphic inline cache keys ("shapes")
to fast-path same-origin accesses, and check all others for complete
mediation. This work is happening in SpiderMonkey now. It will not
relieve us of compatibility requirements for split windows, but it
might allow us to bind |this| to the inner window. That doesn't say we
*should * so bind in the HTML 5 spec, of course.
IIRC from the March meeting, you and Waldemar were in favor of binding
|this| etc. to the inner window. I believe if we had done that in
Mozilla starting with Firefox 1.5 (when split windows were finally
implemented) we would have had significantly more exploits than we
have had given the "outerizing" defense we chose.
Of course you shouldn't be able to tell whether |this| binds to inner
or outer window, except when attacking a browser that access-checks
only via the outer window. One that checks all accesses would stop all
attacks, even when the inner-window capability leaked.
If we must have split windows in all top browser implementations (so
the argument goes), then we must have them in a spec. If not ECMA-262,
then HTML5. If split windows, then what |this| binds to (outer or
inner) needs to be spec'ed. So here we are. Comments?
> The ability to "use lexical scope" (however the syntax turns out)
> and make the global variables truly lexical bindings in a top-level
> environment, not properties of some grotty object, is something I
> look forward to in Harmony:
> Es-discuss mailing list
> Es-discuss at mozilla.org
More information about the es-discuss