Whitelist WeakSet
David Bruant
bruant.d at gmail.com
Tue Sep 25 01:22:14 PDT 2012
Le 25/09/2012 02:05, P Horwat a écrit :
> On 09/24/2012 01:24 AM, David Bruant wrote:
>> Le 24/09/2012 10:04, Tom Van Cutsem a écrit :
>>> Right. Perhaps what Herby meant is that the proxy might provide a
>>> malicious whitelist to steal the names being looked up in them. This
>>> will be prevented by requiring the whitelist to be a genuine,
>>> built-in WeakSet. The proxy will use the built-in
>>> WeakSet.prototype.get method to lookup a name in that whitelist, so
>>> a proxy can't monkey-patch that method to steal the name either.
>> True. I think a lot of that part depends on how WeakSet/Set are
>> spec'ed. It might be possible to accept proxies wrapping WeakSets
>> (which is likely to be helpful with membranes) and perform the check
>> on the target directly, bypassing the proxy traps. Or maybe consider
>> the built-in WeakSet.prototype.get method as a private named method
>> on the weakset instance and only call the unknownPrivateName trap.
>
> Yes. This was bothering me during the meeting and (as far as I know)
> didn't get resolved. What if someone passes in a proxy to a WeakSet
> instead of an actual WeakSet?
>
> A. Allowed. Then the security protocol is utterly broken.
I disagree. Some definitions first:
1) Any proxy has a target. If this target is a proxy, it has a target,
etc. Let's call that a *proxy chain*. Eventually, the target has to be a
non-proxy object. Let's call that the *end-target*.
2) WeakSets are not spec'ed, but let's say for now each instance has
internal own private-named [[add]], [[remove]] and [[has]] method. The
public-facing methods on WeakSet.prototype just call the internal ones:
WeakSet.prototype.has (called with |this| and an object o):
1. let weakset be |this|
2. let has be weakset.[[has]] // [[has]] is a private name.
3. return has(weakset, o)
So now, let's study the following:
var ws = new WeakSet();
var n = new Name();
ws.add(n);
ws = new Proxy(ws, handlerWS); // (3) wrapping and encapsulating the
weakset
var p = new Proxy({}, handlerP, ws); // (1)
p[n] = 37; // (2)
For (1), the Proxy constructor needs to make sure ws is a weakset
instance. Verifying such a thing is not trappable (to prevent proxies to
lie about that), so it an be performed on the object or the end-target
directly, it makes no difference. So it's possible for the constructor
to know that ws is a WeakSet or a proxy to a WeakSet, that part poses no
problem.
For (2), the engine needs to check whether p knows n before calling the
set trap. For that, it can call [[has]] on ws. Since ws is a proxy
itself, [[Get]]-ing its [[has]] private property first requires to make
sure ws knows the private name. It does not (3). So
handlerWS.unknownPrivateName is called. If it doesn't throw, the
operation is transparently forwarded to the target. Likewise when it's
calling the [[has]] internal method on ws; forwarded to the target after
handlerWS.unknownPrivateName decided not to throw.
In this last paragraph, I've demonstrated a way for the whitelist to be
a proxy to a weakmap without ever needing to leak private names. It all
rely on the internal [[has]] of weakset instances to be a private name
known to no one. Being a private name is just for spec economy since the
name will never be visible to any client code.
David
More information about the es-discuss
mailing list