direct_proxies "problem"

David Bruant bruant.d at gmail.com
Fri Jan 11 01:16:07 PST 2013


Le 11/01/2013 06:46, Nathan Wall a écrit :
> David Bruant wrote:
>> For the long term, I expected DOM objects could be proxified.
>> Boris convinced me otherwise for DOM Nodes at least.
> Are you so convinced that the `unknownPrivateSymbol` trap is necessary?
I would think so, for instance, when one wants to revoke access to a 
given object, one needs to be able to throw and for that a trap must be 
called also when the private symbol is unknown, this is a defensive 
scenario too.
Imagine the following scenario:
Untrusted code A is given access to a graph of objects through a 
membrane. Likewise for B with a different membrane. If both A and B have 
access to the same target, each through a proxy of their respective 
membrane.
Now, you want to revoke access to all their membrane (including the 
shared target) to both A and B, because you don't want A and B to be 
able to communicate anymore.

If there is no unknownPrivateSymbol trap, A and B can continue to 
communicate through the private property on the shared target (through 
their respective proxy to it) and you have no way to prevent that. Even 
freezing the object wouldn't work apparently.

>> It's been decided early that a Proxy.isProxy method should be avoided,
>> because proxies should be indetectable from the objects they try to
>> emulate from the ECMAScript perspective
> I thought part of the goal in ES6 was striving to make the DOM emulable (dare I say implementable?) in pure ES.
I'm working for this to happen and it seems to be shared by TC39 (which 
I'm not part of)

> If that's the case, the inability of DOM objects to be proxied sounds like a big deal.
>
> (A) If a proxy is allowed to have a DOM node as its target, but `element.appendChild(proxiedNode)` throws, then you can detect if an object is a proxied DOM node based on whether it throws when you call `appendChild`:
>
>      function isNodeProxy(node) {
>          try {
>              return node instanceof Node &&
>                  document.body.appendChild(node) &&
>                  !!document.body.removeChild(node);
>          } catch(x) {
>              return false;
>          }
>      }
Leaking the information that the node is actually a proxy is due to a 
DOM API issue (which is way way too late to fix obviously).
If you want proxied node to go in the tree, you'll need to find an 
answer to the issue Boris Zbarsky brought up about selector matching 
[1]. I've given up [2], but I'm curious to know if there is a decent 
solution.

You're however not saying how this leak may be a problem for 
self-hosting (emulating in pure ES) the DOM. I'm addressing that after 
answering to your B.

> (B) If a proxy isn't allowed to have a DOM node as its target and ES objects have no way to refuse being proxied, then the DOM is allowed to do something ES can't, widening the gap.
I'm in favor of allowing nodes to be used as proxy targets and having 
the Reflect API [3] work on them as expected, yet forbidding their use 
in DOM tree manipulation methods.


Assuming nodes can be proxied and proxied node are refused to be 
appended. How can this be implemented in pure ES?
All non-proxy nodes are created internally (via HTML parsing) or through 
document.createElement (are there others?), so, the DOM can keep a list 
of the exact objects belonging to the document and refuse appending 
*any* other object (discriminated with object identity) including 
proxied nodes.

> A consistent approach might be having some way for an ES object to refuse being proxied, but It still sounds to me like the real problem is the `unknownPrivateSymbol` trap.
>
> If you take this trap away, wouldn't that let DOM objects be proxied? If you leave this trap there, library authors who want the same level of integrity as the DOM developers want will avoid symbols and try to come up with a WeakMap solution (which will require a bit of legging to work with inheritance I now realize, but I think it can be done).  Who knows, if a good enough WeakMap micro-library is worked out that can come close to simulating symbols without the `unknownPrivateSymbol` problem, private symbols may even become an anti-pattern. Or security-minded developers might just retreat back into closure-classes. Are there good enough reasons to leave the `unknownPrivateSymbol` trap at such an expense?
I set up a use case above. If you have an alternative, I'm listening.

> What does `unknownPrivateSymbol` gain? Someone can always write around it with WeakMaps and closures.
In the above setup, if A and B shared a weakmap, the weakmap had to go 
through the membrane before being shared and at least one of the 2 has a 
membraned version, so its access will be cut when the membrane is revoked.

Thinking a bit more about how A and B can share things, I'm realizing 
that anytime they want to share a private symbol, they have to do it 
through a "capturable" channel (set trap value argument, etc.). So if A 
and B are in touch, the membrane could capture all private symbols going 
from one side to the other and add it to the membrane whitelist. This 
way, anytime there is a communication attempt via private symbols, the 
private symbol is known and the non-unknownPrivateSymbol trap is called.
In theory, it makes the unknownPrivateSymbol not absolutely necessary 
for this use case.
In practice, to capture all communication, anytime the membranes 
intercept a new symbol, it needs to make sure it wasn't used on any 
other object previously shared between both parties and that means 
traversing entire graphs of objects which may be an enormous amount of 
work degrading performance.
I'm also not a big fan of retroffiting control afterwards.

> One thing I have read is it could help in the case of a read-only proxy which would throw anytime `unknownPrivateSymbol` is called with a "set" invocation, but that doesn't really ensure an object is any more read-only than without `unknownPrivateSymbol` if the object just avoids symbols.
I think I suggested that to promote the idea of passing the original 
operation as a second argument of the unknownPrivateSymbol trap. It's 
not been agreed on.
One main use case for proxies is using them as intermediary. If there is 
a circumstance (like private symbol properties) where the proxy can be 
entirely bypassed, then, that use case fails to be fulfilled.

David

[1] https://mail.mozilla.org/pipermail/es-discuss/2013-January/027952.html
[2] https://mail.mozilla.org/pipermail/es-discuss/2013-January/027955.html
[3] http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api


More information about the es-discuss mailing list