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.)
Nathan
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss