How to ensure that your script runs first in a webpage

David Bruant bruant.d at gmail.com
Fri Feb 3 15:14:15 PST 2012


Le 03/02/2012 23:26, John J Barton a écrit :
> On Fri, Feb 3, 2012 at 1:08 PM, David Bruant <bruant.d at gmail.com> wrote:
>> Le 03/02/2012 17:54, John J Barton a écrit :
>>> iframes seem to be effective for the cases David outlined.
>> I can come up with more use cases ;-) Regardless of use cases iframes
>> will always have an overhead against just loading some code with
>> attenuated authority.
> To support the attenuation of authority you have to create a container
> (authority boundary) and you have to attenuate the API you give the
> loaded code.  These activities are not free.
I've been looking at Caja's code recently [1] and noticed that they take
(untrusted) code and eval it. Of course, doing a dummy eval would be
harmful because eval evaluates with the lexical environment of the
calling context. Instead, they've found a way to wrap the eval call and
make that when the eval code accesses something, they get to decide what
this value is. In a way, they provide the lexical environment of their
choice.

A second argument to eval to provide a lexical environment could make
things easier. Just to be clear, I am not suggesting a second argument
like it was before [2]. The object properties would be the lexical
environment of the eval code (and not the lexical environment of the
function if what is provided is a function as second argument). It seems
to me that such a solution would enable fine granularity attenuated
authority at a very small cost:
------
// codeInString:
localStorage.set('a', 1);
var a = localStorage.get('a');
localStorage.set('b', 2);

// ...
var codeInString = // code above, but as a string
var chosenKey;
var oneSlotLocalStorage = {
  get: function(key){
     if(typeof chosenKey === 'string')
         return localStorage.get(chosenKey, val);
  }
  set: function(key, val){
    if(!chosenKey || chosenKey === key){
        chosenKey = key;
        localStorage.set(chosenKey, val);
    }
    else{
        throw new Error('You're not allowed to use more than one key!')
    }
  }
}

eval(codeInString, {localStorage:oneSlotLocalStorage});
// 'a' is chosen as the key and an error is thrown when trying to set 'b'.
-----
Of course, it's a dummy example (and the second eval argument doesn't
exist), but it seems that this kind of attenuation will be far cheaper
(especially when direct proxies will be deployed) than iframes which
always recreate an entire environment (ECMAScript built-ins, DOM
built-ins, a document instance, etc.)



> For the container, the important question (which I do not know the
> answer to): can the container be isolated from the rest of the Web app
> running in the window? Is there any impact on the rest of the
> application from the choice to allow untrusted code to be loaded into
> it?
If the second argument of eval is what you call a container, then yes,
you can fully isolate this code. The only threat remaning threats
(besides bugs in your isolation code) is DoS (if the scripts decides to
allocate infinite memory or to get stuck in an infinite loop).


> To ask the same question in a more personal way: I've read code with
> PropertyDescriptor/freeze() etc. Will I have to write that kind of
> code?
Considering the idea of the eval with a second argument from above, the
answer is: it's up to you. If you want to freeze your objects, do it. If
you feel like passing attenuated APIs as I showed above is enough to
enforce the security you need, then, don't freeze your objects.


>> For instance, if we want to create a game where participants submit some
>> code to compete with each other. When loading the participants code,
>> iframes can have a performance issue and asynchronous communication as
>> done in the browser (with HTML5 cloning algorithm as the "richest form
>> of sharing") may be very limitating.
> Both technologies require the attenuated API. Since this API is the
> security hole, it will require a great deal of attention. I think in
> practical cases this effort will dwarf other issues.
I'm not sure I understand. What do you call "the attenuated API".
Especially for iframes, there is currently no API besides
postMessage/onmessage event in the different-origin case.

>> However, being able to load the
>> code in the same frame ("vat" as said in the concurrency strawman) would
>> certainly yield better performance.
> I thought this way as well only a few months ago. But the Chrome
> multi-process architecture convinced me to reconsider. Integration
> calls, the kind of API a security barrier can support, are just not
> performance sensitive by design.
It's an overhead anyway. Maybe constant, maybe small, but that's an
overhead.

> And JSON messaging performs very well.
It requires a copy. Maybe it's not big, but it's an overhead you can
avoid as well.

What I'm advocating here is the same security properties without the
overheads. Maybe these overheads are small, but they exist by design.

>> The only remaining threat would be DoS (both in memory and CPU time), an
>> alternative allowing performance, rich interaction and preventing by
>> design DoS is what is presented on the concurrency strawman. But we're
>> not there and iframes are far from providing the same level of control.
> Will the security solution prevent the untrusted code from
> manipulating the DOM tree outside of a specific element?
Considering the 2-argument eval example from above, you could define a
'document' property is the second argument and this document (what the
eval code gets when it asks for the "document" variable) could be an
emulation of an HTMLDocument, but forward all (relevant) calls
(appendChild...) to a given element you've chosen.

It seems it could be easily implemented.

> (I appreciate your answers even if my questions sound pointed)
I appreciate the questions, this discussion is enriching as far as I'm
concerned.

David

[1]
http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#513
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=442333


More information about the es-discuss mailing list