On Scope And Prototype Security
I'm really having a hard time understanding where the security issue is here. From what I understand, you've properly hidden the "Private" constructor. I am not surprised if code can reach the [[Prototype]] of an instance and I wouldn't consider that a flaw. I would consider that the [[Prototype]] is part of the object and accessing the [[Prototype]] is like accessing a property or the [[Class]], it's just introspection.
David
Le 17/03/2013 03:04, Andrea Giammarchi a écrit :
My concern is about being unable to let "anyone" retrieve that property, for introspection or to pollute it or change it being able to make my private constructor insecure. In the example there but in other situation I cannot freeze the prototype and yet I cannot hide it from outside in a meaningful way.
AFAICT it looks like "just introspection" for something able to make private classes basically impossible is not a security concern so thanks for your answer, now I know there's no way to have that behavior now, neither tomorrow (so, long story short: good to know)
br
Le 17/03/2013 18:09, Andrea Giammarchi a écrit :
My concern is about being unable to let "anyone" retrieve that property, for introspection or to pollute it or change it being able to make my private constructor insecure. In the example there but in other situation I cannot freeze the prototype and yet I cannot hide it from outside in a meaningful way.
I see. I understand better why you change Private.prototype.init in the middle. A solution here would be to have a single function starting with "if(domReady)" is which "domReady" is a boolean which value changes at the 'DOMContentLoaded' event. I won't pretend it's a perfect solution, but it works. A sufficiently smart interpreter could notice that the domReady value is never set to true after it's moved to false, so could remove the test (but I can already hear Andreas Rossberg about my over-optimism of what JIT-compilers do in practice :-) )
AFAICT it looks like "just introspection" for something able to make private classes basically impossible is not a security concern so thanks for your answer, now I know there's no way to have that behavior now, neither tomorrow (so, long story short: good to know)
I'd like you to express more formally what property you're trying to defend. My understanding is the following: You have a constructor (and its .prototype property). You want to be able to change properties of the .prototype at any point in time, while providing instances generated by the constructor to some mixed trusted code.
Expressed this way, one can notice that giving access to an instance implies giving access to the full [[Prototype]] chain (because of Object.getPrototypeOf and proto in browsers supporting that), so anyone with access to an instance has access to the objects that are kept mutable, making the problem unsolvable.
In my opinion, the issue is not in allowing access to [[Prototype]] but in expecting everything to be always mutable.
Other than the "if(boolean)" solution above, a different solution could involve mixins.
A different (but admittedly complex and too heavy for the problem at hand) solution could involve putting a proxy as .prototype. This proxy doesn't allow mutation (throw on set trap or whatever), but whoever has access to the underlying target (which can be kept private) can still modify it.
My point is that access to the prototype chain isn't an insecurity in essence.
David I do not use, neither have a problem, with the example code but I have used runtime prototype changes for state-machine like applications.
It is not possible to secure or make a class hidden, it was possible before the introduction of proto and Object.getPrototypeOf in ES3, now this is gone, and this was my security concern.
Changing runtime prototype methods can be extremely powerful, just think, as example, about an object used on the DOM with handleEvent and the possibility to change behavior, using same DOM methods, through a single prototype that changes accordingly with the user pointer (muse, pen, touch, etc ... no need to invalidate all listeners and reassign a new one, just change behavior though instances prototype)
There are many cases where changing runtime prototype, mutating, dropping, whatever, can be used and it would be cool to secure nobody can retrieve it outside the private scope.
Again, it was possible, now it's not possible anymore.
Andrea Giammarchi wrote:
It is not possible to secure or make a class hidden, it was possible before the introduction of proto and Object.getPrototypeOf in ES3, now this is gone, and this was my security concern. ... Again, it was possible, now it's not possible anymore.
By "anymore" you mean since 1998 or so? proto is very old.
so is parent ... in the Mozilla world, not in every browser. So your point is that proto is a good thing I guess, I thought it was rather a mistake.
Moreover, I am talking about the standard Object.getPrototypeOf() which has been introduced recently, not in 1998, and there's no mechanism to prevent it to return the prototype.
I understand now security is highly subjective here and private classes should not exist in a programming language.
Again, good to know
Andrea Giammarchi wrote:
so is parent ... in the Mozilla world, not in every browser.
That's irrelevant and also it was never writable.
So your point is that proto is a good thing I guess, I thought it was rather a mistake.
I didn't say that. I just said it is old.
Moreover, I am talking about the standard Object.getPrototypeOf() which has been introduced recently, not in 1998, and there's no mechanism to prevent it to return the prototype.
SES and similar "prepared environment" dialects can and do handle things like Object.getPrototypeOf (and proto).
I understand now security is highly subjective here and private classes should not exist in a programming language.
No one said private classes should not exist. David mentioned traits. ES5 provides tools for high-integrity abstractions. See traitsjs.org.
traits are not private classes, are constant overwrites or the equivalent of Object.create(Object.prototype, instanceDescriptors); which does not allow runtime modification of all instances at once so it does not make state-machines easy and secure to develop via JS.
Is there any mechanism in any future specs that does not let Object.getPrototypeOf(object) return the prototype and return null instead ?
Object.hidePrototypeOf(object)
I believe no, that's why I've raised the question in first place.
"does not allow runtime modification of all instances at once" meant through inheritance, through the proto, and its methods ...
this is probably going to be easier .. let's see if somebody can understand what I mean:
var public = (function(){ var private = { // everything I know about security in ES // is that everything able to accesses // the private scopes has been removed... // Here I have my own, private, object // and nobody out there should be reach it. // but it's impossible to grant such achievement // if the instance is used through inheritance // so that outside there could be simply puppets // all of them managed behind the scene }; return Object.freeze( Object.create(private) ); }());
alert(public.test); // undefined
// why I cannot avoid this? I'd LOVE to! Object.getPrototypeOf(public).test = 123;
alert(public.test); // 123
I hope this is more clear now but feel free to ask more.
Best
On Tue, Mar 19, 2013 at 5:06 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:
this is probably going to be easier .. let's see if somebody can understand what I mean:
var public = (function(){ var private = { // everything I know about security in ES // is that everything able to accesses // the private scopes has been removed... // Here I have my own, private, object // and nobody out there should be reach it. // but it's impossible to grant such achievement // if the instance is used through inheritance // so that outside there could be simply puppets // all of them managed behind the scene }; return Object.freeze( Object.create(private) ); }());
alert(public.test); // undefined
// why I cannot avoid this? I'd LOVE to! Object.getPrototypeOf(public).test = 123;
alert(public.test); // 123
I hope this is more clear now but feel free to ask more.
When I freeze the private object, it silently rejects the attempt to define an expando:
var public = (function() { var private = {};
Object.freeze(private);
return Object.freeze(
Object.create(private)
);
}());
console.log(public.test); // undefined
Object.getPrototypeOf(public).test = 123;
console.log(public.test); // undefined
Not sure if that covers all of the cases you had in mind.
On Tue, Mar 19, 2013 at 5:06 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:
this is probably going to be easier .. let's see if somebody can understand what I mean:
var public = (function(){ var private = { // everything I know about security in ES // is that everything able to accesses // the private scopes has been removed... // Here I have my own, private, object // and nobody out there should be reach it. // but it's impossible to grant such achievement // if the instance is used through inheritance // so that outside there could be simply puppets // all of them managed behind the scene }; return Object.freeze( Object.create(private) ); }());
alert(public.test); // undefined
// why I cannot avoid this? I'd LOVE to! Object.getPrototypeOf(public).test = 123;
alert(public.test); // 123
I hope this is more clear now but feel free to ask more.
If you avoid the strict mode future reserved words...
void function() { "use strict"; var outer = (function(){ var inner = {};
Object.freeze(inner);
return Object.freeze(
Object.create(inner)
);
}());
console.log(outer.test); // undefined
// Throws a TypeError, indicating that the object is not extensible! Object.getPrototypeOf(outer).test = 123;
console.log(outer.test); // undefined }();
Le 19 mars 2013 à 21:53, Andrea Giammarchi <andrea.giammarchi at gmail.com> a écrit :
Is there any mechanism in any future specs that does not let Object.getPrototypeOf(object) return the prototype and return null instead ?
Object.hidePrototypeOf(object)
Object.hidePrototypeOf = function(target) { return Proxy(obj, {getPrototypeOf: target => null}) }
2013/3/17 Andrea Giammarchi <andrea.giammarchi at gmail.com>
There are many cases where changing runtime prototype, mutating, dropping, whatever, can be used and it would be cool to secure nobody can retrieve it outside the private scope.
So basically you want to give a third party an object which has a prototype that you want to be able to mutate, but you want to prevent the other party from mutating it? That sounds like a Proxy.
var Public = (function () { var Private = { foo: 'bar' };
var proxy = new Proxy(Private, { set: function () { // do nothing } });
return Object.create(proxy); }());
console.log(Public.foo); // 'bar' Object.getPrototypeOf(Public).foo = 123; console.log(Public.foo); // 'bar'
Juan
var public = (function(){ var private = { }; return Object.freeze( Object.create(private) ); }());
// why I cannot avoid this? I'd LOVE to! Object.getPrototypeOf(public).test = 123; alert(public.test); // 123
At first, I thought you were right - proto is an object property, so there should be a way to turn it into a private property (assuming ES6 will have such).
Then I thought, it would have to be protected, not private - if I extend the prototype chain further down, I should still be able to go up through this proto here, right?
My current thinking is still different: proto is not a normal object property, it is an implementation shorthand for extending an object. If we were to copy all the methods from the prototype chain into a single "class" object, that would serve the same purpose, the proto links just save space.
In other words, you want to protect/make private the properties of the objects that proto points to, and those objects themselves, not the proto link.
For that purpose, a deep chain freeze, following the prototype chain, and freezing all objects in it, would be less confusing/error prone than the shallow Object.freeze we have. Apart from the fact that sharing of objects in the chain might freeze someone else's prototypes.
Claus
oh dear ... even the example did not explain ... how can that be ?
@Rick is not because of my alzheimer that I did not freeze the private object. I want to manipulate that because that's my object and I want to expose objects that inherits from it without giving anyone the possibility to reach my private, own, object!
I don't want to be able to freeze the object, I don't want anyone "out there" to even reach it ... via proto or getPrototypeOf, got it?
@Juan I don't want the complexity of a Proxy, I want objects that inherit from my private object so that what changes in my private object reflects automatically everywhere. There is no need to Proxy, IMHO, this stuff was again already possible in ES3 ignoring proto, I am talking about standards. However, if you want, Proxy is more or less what I meant with the private object.
@Claus proto is a disaster, if you ask me, but the problem is that even if proto disappears, as it should, there is still Object.getPrototypeOf(object) able to retrieve my private object.
@Claude ... the example goes close, but it won't work as it is and it cannot be used as generic method, isn't it ? Also that suffers from the fact that I cannot hide runtime, I need to hide first, and send the Proxy result or the proto won't be hidden, right?
@all ... bear in mind, my example works already in ES3 ... you can try it in IE 5 ... I am not kidding ... there's no Object.getProottypeOf(object) there, neither object.proto
Best
since I wrote about it, the IE5 example ...
var Puppet = function (Object) { var freeze = Object.freeze || Object, master = Master.prototype; function Master() {} function Puppet() { freeze(this); } master.constructor = Puppet; Puppet.prototype = new Master;
// for testing sake setTimeout(function(){ master.name = 'puppet'; }, 0);
return Puppet; }(Object);
var o = new Puppet, output = [o.name];
o.name = 'master'; output.push(o.name);
setTimeout(function () { output.push(o.name); alert(output.join('\n')); // undefined // undefined // "puppet" }, 10);
If freeze is not available in IE5 it does not actually really matter. The point/concept is about having an hidden prototype.
br
2013/3/19 Andrea Giammarchi <andrea.giammarchi at gmail.com>
@Juan I don't want the complexity of a Proxy, I want objects that inherit from my private object so that what changes in my private object reflects automatically everywhere.
Maybe you're misunderstanding my example. I'm not returning a proxy each time, I'm using a proxy as the prototype of all your instances. That way even though the prototype is accesible with Object.getPrototypeOf(outer), the untrusted party still can't do anything with it. And you can still modify your private object and the change is reflected everywhere.
If you did understand it, then what are we missing?
Juan
missing a) the Proxy, which is nowhere right now if not in Firefox and b) the fact Private won't be prototypeOf instances so there's an intermediate layer to track. The set could also reflect a setter in the prototype, a setter that I might decide to add or swap runtime. I don't see Proxy that flexible because I cannot decide when I want that set should do something else if not passing through internal, runtime swapped, functions bringing the context.
As I've said, your was the closest thing I meant so if there's no way to obtain with new features what was possible in 1998 then I might have no choices and opt for proxies.
I still believe private classes and the ability to make a prototype not discoverable should be part of the language.
As example, I think is kinda weird everybody can modify the Arguments.prototype, even if this could be used to do the most common thing on earth: add slice to it
(function(){return arguments.proto||Object.getPrototypeOf(arguments)}()).slice=[].slice;
// example (function(){ alert(arguments.slice(1)); // 2, 3 }(1, 2, 3));
br
Andrea Giammarchi wrote:
missing a) the Proxy, which is nowhere right now if not in Firefox
Be consistent. You wanted Object.hidePrototypeOf, which is nowhere period, and not on any Harmony standards track. Proxies are in ES6 and under a flag in V8, and ahead of anything like Object.hidePrototypeOf by light-years.
On Tuesday, March 19, 2013, Andrea Giammarchi wrote:
oh dear ... even the example did not explain ... how can that be ?
@Rick is not because of my alzheimer that I did not freeze the private object. I want to manipulate that because that's my object
This wasn't specified in your example code and comments.
and I want to expose objects that inherits from it without giving anyone the possibility to reach my private, own, object!
I don't want to be able to freeze the object, I don't want anyone "out there" to even reach it ... via proto or getPrototypeOf, got it?
Yes, I "got it". Time machines are out of scope for ES6, maybe ES7?
on this example (function(){return arguments.proto||Object. getPrototypeOf(arguments)}()).slice=[].slice;
turned out Arguments is, as example, an hidden class, since arguments.proto is Object.prototype ^__^
(function(){ alert(Object.getPrototypeOf(arguments) === Object.prototype); }());
but [[Class]] of arguments is Arguments
so this is exactly what I meant ... finally I found the perfect example: Arguments ... the class is unreachable, all instances can be manipulated, theoretically, behind the scene to throw, retrieve, or do, whatever.
Rick ... maybe ES7 is better than "NO" or "use something else this is not a problem",
On 3/19/2013 5:17 PM, Andrea Giammarchi wrote:
but [[Class]] of arguments is Arguments
so this is exactly what I meant ... finally I found the perfect example: Arguments ... the class is unreachable, all instances can be manipulated, theoretically, behind the scene to throw, retrieve, or do, whatever.
It's not that it's unreachable...it doesn't exist. The spec doesn't call for some hidden prototype object that properties can be on; it specifies an exotic object type with some different internal methods. Internal methods are not inherited prototypally.
but it perfectly represent what I'd like to achieve through JavaScript, a "class" or prototype that does not exist out there, but it's defined inside my bloody own prototype!
I have done here, apologies it took so long to provide the right example. Now I'll wait 'till the day that would be possible, usually stuff I propose takes 2 years before it goes out, it won't be the first time even here.
Best
inside my bloody own prototype! ==> my own closure/private scope
FIY the Arguments class: svn.webkit.org/repository/webkit/trunk/Source/JavaScriptCore/runtime/Arguments.cpp
and to do not drop fireballs and run, me two years ago here: (recently basically specced as Object.getPropertyDescriptor) esdiscuss/2011-October/017076
so maybe I am not always that crazy when I ask about things and propose stuff ... just maybe.
Thanks for listening
That conversation on
fn. caller
left me many doubts about extra things too.As example, I understand the fact a function that do not want to be accessed should not be accessed when any accepted object could due tweaked to retrieve it via caller, that's OK, but what about private "classes" and the fact there's no way to ensure them private?
Despite the sense, the good and the bad, this is perfectly valid JS code:
var myNameSpace = function () {
var queue = [];
function Private() { this.init(); }
function initBeforeDOM() { queue.push(this); }
function initAfterDOM() { // do stuff }
Private.prototype.init = initBeforeDOM; window.addEventListener('DOMContentLoaded', function(){ Private.prototype.init = initAfterDOM; queue.forEach(function (instance) { initAfterDOM.call(instance); }); });
// trying to make Private inaccessible Object.defineProperty( Private.prototype, 'constructor', {value: Object, enumerable:false, writable:false, configurable:false} );
return { generate: function () { return new Private; } }; }();
var o = myNameSpace.generate(); var proto = Object.getPrototypeOf(o); alert(proto.constructor); alert(proto.init);
Above code is also based on few concepts I always found cool about JS like the possibility to mutate all objects at once through the prototype, usually considered a bad practice, but technically the best/fastest/memory-safe way we have in JS to create state machines behaviors through distributed instances so ... way too cool
Well, I've got a problem, even if the constructor might be unreachable, there is something I cannot secure at all which is the constructor prototype.
Not a single mechanism, in current JS, lets me make a prototype safe from operations, potentially nasty and disastrous, as
Object.getPrototypeOf(generic)
is.Thoughts? Thanks.