direct_proxies "problem"

Nathan Wall nathan.wall at
Sat Jan 12 14:54:02 PST 2013

Thank you for the thoughtful reply. You sufficiently answered many of my concerns related to DOM, but I want to focus on the need for the `unknownPrivateSymbol` trap.

David Bruant wrote:
> 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.

My reply concerning this is below.

> 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.

I have an idea, but I'm going to think through it some more and possibly post it as a separate reply later to keep this reply more focused.

> 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.

That makes sense. Conceded.

> 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.

Ok, I think I understand now.

Here's how I'm imagining it: So if A shares object O with B, the membrane may wrap O in proxy P. O may have a private symbol properties M and N, where the property for symbol M actually points to symbol N:

    let O = { },
        M = new Symbol(true/* private */),
        N = new Symbol(true/* private */);
    O[M] = N;
    O[N] = null;

When A shares O with B, the membrane will not be able to see either one of these symbols.

Let's assume no `unknownPrivateSymbol` trap.

The objects cannot yet communicate without the membrane knowing because B does not know O's private symbols.

Later if A shares private symbol M with B, the membrane will intercept the symbol and add it to the whitelist before passing it along. Now the membrane knows about M but it can only learn about N by searching all previous communications for M. The membrane could in theory discover N by searching previous communications for M and finding N in O.  I agree with you though that this is a pretty huge overhead for the membrane to have to do, so let's look for another way.

If the membrane fails to search O for M, then B can discover N under-the-hood -- that is, B gets access to a private symbol that the membrane doesn't have on its whitelist.

However, what if the membrane, instead of passing along M, creates a new private symbol M2, and this is the actual symbol shared with B. Now if B checks O for property M2 it will not be able to uncover the symbol N.  The membrane adds M2 to its whitelist and anytime B tries to send M2 back to A, the membrane converts it to M (and vice versa). Therefore, A always sees only symbol M and B always sees only symbol M2.

Does this work and allow us to do without `unknownPrivateSymbol`?

(An even easier alternative is that the membrane could prevent sharing private symbols.)


More information about the es-discuss mailing list