Le 19/01/2012 06:44, Brendan Eich a écrit :
Use __proto__ in object literals to do a put (assuming that a __proto__ getter/setter was created in Object.prototype) instead of a defineProperty? All modes or only nonstrict mode? Allen: Make such use of __proto__ to be a synonym for <|. If a <| is already present, it's an error.
DaveH: __proto__ is ugly.  Don't want it in the language forever.
Waldemar: What about indirect [] expressions that evaluate to "__proto__"? In Firefox they evaluate to accesses that climb the prototype chain and usually reach a magic getter/setter-that-isn't-a-getter-setter named __proto__ that sits on Object.prototype. MarkM: Likes the ability to delete __proto__ setter and thereby prevent anything in the frame from mutating prototypes.
Waldemar: How do you guard against cross-frame prototype mutations?
DaveH: __proto__ is in the "omg, what were we thinking" category.
Waldemar: Opposed to making __proto__ mutate prototypes other than at object construction. This is getting insanely complex.
Unresolved.

One point not recorded here: given MarkM's argument for Object.prototype.__proto__ as the one property to delete to remove this old beast, what kind of property does that appear to be to ES5's Object.getOwnPropertyDescriptor? Arguments pro and con for data property (as it appears to be in SpiderMonkey) vs. accessor (JSC intended to move to that from its hardcoded magic id handling in Get and Put code).

Argument for data property facade: an accessor allows extracting the setter from the property descriptor, call it stolen__proto__setter. Then if one makes an object with a bespoke proto-object but not delegating to Object.prototype:

  var o = { __proto__: Object.create(null) };

an attacker could mutate o's [[Prototype]] via stolen__proto__setter.call(o, evil_proto). This is not possible if Object.prototype.__proto__ reflects as a data property, because o's two-level proto chain is cut off from Object.prototype, so no further means of updating [[Prototype]] is available.
Every time I've been thinking of an issue like this, the solution I've found was "whoever runs first wins".
Assuming __proto__ is an accessor of Object.prototype:
If trusted code runs first, it can protect itself by removing the setter and making the property non-configurable.
If an attacker runs first... you're screwed as you made the demonstration.

Even in the data property case, if an attacker runs first, she can probably change quite a lot of built-in prototypes, change built-in properties (of any object it has access to) to non-configurable accessors, add loggers, all over the place, return evil values to function calls. I have a script [1] which replaces every function with a function that is semantically equivalent, but logs "this", the arguments and the return value. If an attacker runs this before any other script (before initSES.js, for instance :-° ), but adds more harmful than loggers, she can really do nasty stuffs.

It seems that the threat may be a bit smaller if __proto__ is a data property, but I'm not sure it's significantly smaller than all the things you can already do if an attacker runs first.

If you run first, __proto__ being an accessor or a data property does not make a difference, you can protect yourself in any case. The accessor has the advantage that you can have fine-grained control over who can change and what cannot. Specifically, you can bind __proto__setter, and share this with someone so that this party can change the prototype of a given object (or set of objects) you've chosen. A data property is more "all (everyone can change the prototype of every object inheriting from Object.prototype) or nothing (or no one can change the prototype of any object)".


The question that remains is "how can you make sure your trusted run first?" which, I think goes beyond ECMAScript scope and should be considered in each context (browser, node.js, etc.)

For the browser, I can't think of a good solution that would be backward compatible and efficient. Suggestions welcome.

David

[1] https://github.com/DavidBruant/JSTraversers (not really production ready and makes some browser crash or hang, because they don't seem to appreciate their DOM builtins being traversed)
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to