W3C home > Mailing lists > Public > public-webapps@w3.org > January to March 2014

Re: [webcomponents] Encapsulation and defaulting to open vs closed (was in www-style)

From: Maciej Stachowiak <mjs@apple.com>
Date: Thu, 13 Feb 2014 18:00:54 -0800
Cc: Elliott Sprehn <esprehn@chromium.org>, Dimitri Glazkov <dglazkov@chromium.org>, Arthur Barstow <art.barstow@nokia.com>, "public-webapps@w3.org WG" <public-webapps@w3.org>, Erik Arvidsson <arv@chromium.org>, Boris Zbarsky <bzbarsky@mozilla.com>
Message-id: <789CB16F-AE65-4A64-87D1-B2FEC65BFAE8@apple.com>
To: Alex Russell <slightlyoff@google.com>

On Feb 13, 2014, at 4:01 PM, Alex Russell <slightlyoff@google.com> wrote:

> On Thu, Feb 13, 2014 at 1:25 PM, Maciej Stachowiak <mjs@apple.com> wrote:
> 
> On Feb 12, 2014, at 4:04 PM, Alex Russell <slightlyoff@google.com> wrote:
> 
>> 
>> 
>> In discussion with Elliot and Erik, there appears to be an additional complication: any of the DOM manipulation methods that aren't locked down (marked non-configurable and filtered, ala caja) create avenues to get elements from the Shadow DOM and then inject styles. E.g., even with Arv's lockdown sketch: 
>> 
>>   https://gist.github.com/arv/8857167
>> 
>> You still have most of your work ahead of you. DocumentFragment provides tons of "ins", as will all incidentally composed APIs.
> 
> I'm not totally clear on what you're saying. I believe you're pointing out that injecting hooks into the scripting environment a component runs in (such as by replacing methods on global protototypes) can allow the shadow root to be accessed even if no explicit access is given. I agree. This is not addressed with simple forms of Type 2 encapsutation. It is a non-goal for Type 2.
> 
> I'd like to understand what differentiates "simple forms of Type 2 encapsulation" from other potential forms that still meet the Type 2 criteria. Can you walk me through an example and show how they would be used in a framework?

Type 4 encapsulation would also meet the Type 2 criteria, for example.

The difference is that with "simple" Type 2 you do not attempt to protect against a pre-poisoned scripting environment. I would be satisfied with Type 4 (if it's usable) but it is much harder to spec as you need it to give rigorous security guarantees.

>  
>> This is fraught.
> 
> Calling something fraught is not an argument.
> 
> Good news! I provided an argument in the following sentence to help contextualize my conclusion and, I had hoped, lead you to understand why I'd said that.

Your argument seems to be based on an incorrect premise.

>  
>> To get real ocap-style denial of access to the shadow DOM, we likely need to intercept and check all DOM accesses. Is the system still usable at this point? It's difficult to know. In either case, a system like caja *can* exist without explicit support....which raises the question: what's the goal? Is "Type 2" defined by real denial of access? Or is the request for a fig-leaf (perception of security)?
> 
> Type 2 is not meant to be a security mechanism.
> 
> I'd like to see an example of Type 2 isolation before I agree to that.
>  
> It is meant to be an encapsulation mechanism. Let me give a comparison. Many JavaScript programmers choose to use closures as a way to store private data for objects. That is an encapsulation mechanism. It is not, in itself, a hard security mechanism. If the caller can hook your global environment, and for example modify commonly used Object methods, then they may force a leak of your data.
> 
> A closure is an iron-clad isolation mechanism for object ownership with regards to the closing-over function object. There's absolutely no iteration of the closed-over state of a function object; any such enumeration would be a security hole (as with the old Mozilla object-as-param-to-eval bug). You can't get the value of "foo" in this example except with the consent of the returned function:
> 
> var maybeVendFoo = function() {
>   var foo = 1;
>   return function(willMaybeCall) {
>     if (/* some test */) { willMaybeCall(foo); }
>   }
> };
> 
> Leakage via other methods can be locked down by the first code to run in an environment (caja does this, and nothing prevents it from doing this for SD as it can pre-process/filter scripts that might try to access internals).

Caja is effective for protecting a page from code it embeds, since the page can have a guarantee that its code is the first to run. But it cannot be used to protect embedded code from a page, so for example a JS library cannot guarantee that objects it holds only in closure variables will not leak to the surrounding page. This is exactly analogous to shadow DOM leakage via DOM methods.

> 
> Getting to closure-strength encapsulation means neutering all potential DOM/CSS access. Maybe I'm dense, but that seems stronger than the "simple form of Type 2".

That seems like a false conclusion to me given the above.

> 
> If you're making the case that it might be helpful to folks trying to implement Type 4 if the platform gave them a way to neuter access without so much pre-processing/runtime-filtering, I could take that as an analog with marking things non-configurable in ES. But it seems you think there's an interim point that developers will use directly. I don't understand that and would like to.

I don't believe Type 4 can be implemented on top of Type 1 with a pre-processing/runtime-filtering strategy. It would require additions to the platform. Filtering cannot create a two-way distrust boundary, only one-way. You would need a mutually trusted agent to provide two-way protection (such as the UA).

> 
> But that does not mean using closers for data hiding is a "fig-leaf" or "attractive nuisance".
> 
> Agreed, but only because they're stronger than you imply by analogy. What I'm arguing is that if closures are the right analogy for some variant of Shadow DOM then they'd need to get MUCH stronger  (Type 4) to meet that charge.

That seems incorrect to me. You're comparing closures + Caja-like prepping of the runtime environment to "naked" Type 2 with no analogous prepping of the runtime environment to provide trusted DOM operations. In an apples-to-apples comparison, it is analogous.

>  
> The proposal is merely to provide the same level of protection for the shadow DOM.
> 
>> 
>> This is the struggle I have with Type 2. I can get my mind around Type 4 and want it very badly. So badly, in fact, that I bore most people I talk to with the idea of creating primitives that explain x-origin iframes (some sort of "renderer worker", how are the graphics contexts allocated and protected? what does it mean to navigate? what sorts of constraints can we put on data-propagation approaches for flowed layouts that can keep us out of security hell?).
> 
> (1) The form of Type 1 encapsulation offered by current Shadow DOM specs cannot explain *any* built-in element that has a compound structure. Because built-in elements do not expose their Shadow DOM. It would be nearly impossible to do that and code them safely. If you want explanatory power for built-ins, Type 1 is not sufficient.
> 
> We agree on that.
>  
> (2) Enabling iframes to be implemented as a custom element would be hard, and goes beyond the bare minimum of Type 4 requirements. That said, as far as I can tell there is no need whatsoever to expose the details of how graphics contexts are allocated to enable this. Why would you think that?
> 
> It's just where the archeology of trying to understand our one iron-clad isolation mechanism (iframes) leads.

I'm sorry, I am not sure I understand that sentence. What does "archeology" mean in this context?

>  
> As I understand it, iframes are primarily about providing a security boundary with some tiny narrowly scoped holes, not about management of graphics resources. You would not use canvas-level primitives to implement iframes. 
> 
>> What I don't understand is what daylight there can be, in practice, between Type 2 and Type 4-by-other-means. Either we lean on convention (using class names for styling) and see how it goes, potentially extracting something like the previously-proposed "::part()" system, or we go down the caja-style rabbit hole and try to lock down _all_ the things, and not just from incidental access.
>> 
>> Where would you have us draw this line?
> 
> I would draw the line between simple, obvious explicit mechanisms whose intended common use amounts to free-form access to the Shadow DOM, and mechanisms that indirectly allow this access by injecting traps into the global environment. Providing a clean global environment is not a goal for Type 2. Nor is a secure membrane for method calls.
> 
> I guess what I'm saying is that the slope from partial-encapsulation (your type 2) to "real" encapsulation (type 4) is steep. If Type 2 looks like it'll keep people out but doesn't, isn't the actual effort to doing so isomorphic to building Type 4 on top of Type 1 (ala caja) or a very small delta on top of it?

I do not think Type 4 can be built on top of Type 1 using a Caja-like strategy in userspace. 

Type 4 needs a trusted scripting environment. You can accomplish that using an iframe-like strategy, a strategy like "isolated worlds" as implemented in Blink or WebKit, or a strategy similar to Caja but provided by the UA without having to trust the embedding page to cooperate. That's the delta over Type 2 (as I understand it).

> 
>> Until we can agree on this, Type 2 feels like an attractive nuisance
> 
> I think you are only calling it an "attractive nuisance" because you did not understand what it is meant to provide, and instead believe it is a broken version of a different feature. It is not. I have tried to explain. I hope my explanation was informative.
> 
> I really am trying. Can you outline use-cases for this type of encapsulation? 

Analogous to when you'd use a closure to hold your state instead of JS object properties, but for a component. I believe this is useful for all use cases listed here: <http://www.w3.org/2008/webapps/wiki/Component_Model_Use_Cases>. In some cases it is not sufficient by itself, as some of these cases need a strong security guarantee.


>> and, on reflection, one that I think we should punt to compilers like caja in the interim. If toolkits need it, I'd like to understand those use-cases from experience.
> 
> Caja cannot solve the Type 2 or Type 4 use cases at all. Caja can be used by the embedder to protect the embedding page from content that it chooses to embed, by validating that it has been transpiled with Caja.
> 
> I'm using it as an analog for the technology that would be necessary to build Type 4 on top of Type 1.

I do not believe Type 4 can be built on top of Type 1 without adding anything more to the platform; certainly not with a Caja-like filtering strategy. Such a strategy is viable only if you can guarantee you are the first code to load in a page, and control loading of all other code. From the perspective of a component loaded in a page it does not trust, it cannot guarantee this.

>  
> But it cannot be used by an embedded component to protect itself from the embedding page. The component has no way to force the page to run all of its script through the Caja compiler, nor to verify that it has done so. If you think more about the security issues I expect it will be clear why it does not solve the problem.
> 
> Given that SD always exists in a scripting context with a shared heap, shared globals, etc., I don't understand how mutual distrust is possible.

It's technologically possible to achieve mutual distrust in ways other than iframes. But it would require the right additions to the platform.

> Iframes allow it and our story for needing strong encapsulation for SD has always been "if you need that, put an iframe in your SD".
> 
> Which use-cases do you have which aren't satisfied by that solution? 

We have actually considered an iframe-based approach to components, at least for the secure model. It has some significant limitations:

- It's super awkward to export an API from your iframe. If you want something nicer, you need script to wrap it in the embedder. But now that script runs in an untrusted scripting environment, so you have to be super careful.
- You can't put insertion points inside an iframe, so you can't have a component that is both trusted and a container for light dom content.
- To achieve flexible layouts, you need seamless iframes or equivalent. It's not clear seamless iframes are on the winning track as part of the platform, though. And even then, they can't necessarily achieve all of the layout flexibility that you can get with general CSS styling.



Regards,
Maciej


Received on Friday, 14 February 2014 02:01:23 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 18:14:21 UTC