Nuking misleading properties in `Object.getOwnPropertyDescriptor`

Nathan Wall nathan.wall at live.com
Wed Mar 13 08:26:54 PDT 2013


David Bruant wrote:
> Tom Van Cutsem wrote:
> > To my mind, the blame for the breakage lies with `Object.prototype` 
> > being mutated by the third-party script, not with property descriptors 
> > inheriting from Object.prototype. Thus, a fix for the breakage should 
> > address that directly, rather than tweaking the design of property 
> > descriptors, IMHO. 
> I agree. 
> 
> The first (security) decision any JavaScript application should make 
> would be to freeze all built-ins like SES [3][4] does. (In the future, 
> it could even make sense to add a CSP [5] directive for that) 
> If necessary, the application can first enhance the environment by 
> adding polyfills/libraries and such, but that's pretty much the only 
> thing that's acceptable to run before freezing everything. 

Hey David and Tom.  This is good advice for application authors, but I don't work at the application level; I write libraries.  I don't want to freeze everything because I want to leave the environment open to monkey-patching and shimming by other libraries and the application authors. So this isn't an option for me.

> "what if an attacker switches Array.prototype.push and Array.prototype.pop?"

These are issues that are easy to address by using stored late-bound function references rather than methods and array-likes instead of true arrays.

    var push = Function.prototype.call.bind(Array.prototype.push),
        arrayLike = Object.create(null);
    arrayLike.length = 0;
    push(arrayLike, 'item-1');

As long as the environment is correct when my script initializes, I get all methods I need to use stored inside my library's closure. Freezing isn't needed.

It's also possible to write around the `defineProperty` problem by converting the descriptor into a prototype-less object. However, I actually encountered some performance problems with this. I was able to improve the performance by only dropping the prototype when necessary (as long as `get`, `set`, `value` or `writable` haven't been added to `Object.prototype`, it's not necessary). However, as a matter of principle, my argument is that `Object.getOwnPropertyDescriptor` should, at the bare minimum, return a descriptor that can be known to work in `Object.defineProperty`.  If `Object.defineProperty` doesn't accept it, then you `getOwnPropertyDescriptor` didn't really give me a valid descriptor.

I think that this behavior (1) limits the creativity of developers to define properties like `Object.prototype.get`, (2) is a potential stumbling block, (3) has no real benefit -- really, there's not anything positive about this behavior, and (4) forces developers who want to support `Object.prototype.get` to add an extra layer of cleaning before using `defineProperty`.

Nathan 		 	   		  


More information about the es-discuss mailing list