Re: Summary of major differences between COWL and Suborigins

Thanks so much for writing this up, Joel! (Sorry for my delayed response.)

Joel Weinberger <jww@chromium.org> writes:
> COWL provides a system for labeling data programmatically and setting
> policies on how labeled data may be used. In turn, this restricts
> resources/privileges that a given execution context may access, including
> same origin/host restricted resources such as cookies and storage, and
> cross-origin based resources, such as values received via postMessage() or
> a CORS response.
>
> Suborigins extends the same-origin policy by providing a mechanism for
> creating a namespaced origin. Two execution contexts with the same
> namespace, scheme, host, and port are treated as same-origin, while two
> execution contexts with the same scheme, host, and port but different
> namespaces are treated as different origins and therefore are isolated from
> each other via standard same-origin policy rules.
>
> While COWL and Suborigins differ in many small ways, there are several
> macro differences that are quite important. COWL allows a developer to
> apply the principle of least privilege to trusted but potentially buggy
> code. Suborigins, on the other hand, provide a much coarser grained tool to
> isolate code entirely. Since it places the entire context into a separate
> origin, that context, even if malicious, will never be able to access or
> leak anything that is not explicitly given to the Suborigin.
>
> Thus, the two systems provide fundamentally different, but potentially
> complementary, mechanisms for different threats: COWL for reducing the
> privilege of a context and Suborigins for isolating a context completely.
> These can be used separately for different types of applications or may be
> used in tandem.
>
> For example, consider hosting an untrusted application on
> www.example.com/app. COWL allows us to say that /app doesn’t get access to
> cookies or that postMessage events only get sent to particular origins,
> while Suborigins allow us to say /app gets to treat its cookies as a
> subdomain would and gives us a new namespaced value for event.origin in
> MessageEvents. These are complementary mechanisms. And, of course, it is
> not hard to imagine an application with all of these properties so both
> COWL and Suborigins are useful.

I think this summary is pretty reasonable and accurate. But, I think
that the one big difference (the other is not, see below) is only due to
my being conservative in the COWL spec in reusing sandboxed origin flag
instead of introducing namespaced origins. To explain what I mean,
I'd like to first highlight the similarity between the two specs:

COWL extends contexts with privileges. You can think of privileges as
generalization of origins. By default, a page only has the
privilege corresponding to its origin. But, we can set a header to
specify a weaker "delegated" privilege. For example, for the /maps app
you may wish to set the privilege as such:

Sec-COWL: ctx-privilege 'self' OR app:maps

This ensures that the maps app is privilege separated ("should be
treated as different origin") from another app (say /mail) and the /
app. This disjunction in COWL privileges (a privilege is just a minted
label) is effectively a way of namespacing your origin. (COWL's
privileges also allows for conjunctions, but I don't this part matters
for this discussion.)

I think the key difference between this form of namespacing and that of
Suborigin is that COWL reuses the sandbox flag (and thus doesn't allow
access to cookies) and doesn't modify event.origin in MessageEvents. I
believe the old version of Suborigin was closer to this. While this is
an important difference, it need not be. In particular, I chose the
sandbox approach to avoid having too many features in this version of
the spec. I think that giving namespaced code access to cookies and
modifying MessageEvents is the way to go, but adding labeled storage was
my plan for the future. (This is something we talked about in the OSDI
paper, but like other features, I cut from this version of the spec.)

I think it may make sense for us to chat here on in person (and report
back here) and see if we can find a general mechanism that we can use in
both. (I see the COWL confinement/label enforcement part as complimentary
to Suborigins, but I think there is a subset of privileges that is
trying to achieve the same task as Suborigins.)
 
> Thinking about Cross-Site Scripting specifically, COWL cannot prevent an
> XSS from executing in any part of an origin. Furthermore, even if the
> sensitive data in that origin is restricted, an XSS can always drop
> privileges to a restricted label and exfiltrate the data using side
> channels. However, using COWL, an origin can control what information flows
> into another origin in the first place, potentially recognizing a context
> as vulnerable, it may be able to prevent the accidental leakage of data
> into a compromised application. Suborigins, on the other hand, create a new
> security context, and if an XSS occurs in the Suborigin, it cannot access
> other Suborigins or the original origin. Thus, an XSS can be contained to
> executing within a Suborigin context.

I don't think this is completely true. In particular, if you set the
privilege with the COWL header to a delegated privilege, the page is
effectively of a different origin. For example, if your maps app ships
with the header:

Sec-COWL: ctx-privilege https://google.com/maps OR app:maps

then an XSS script on the maps app should not be able to get at
https://google.com data or http://google.com/mail.  You can additionally
use labels to enforce mandatory access control over data, but that's not
necessary if all you want to do is privilege separate applications.
 
> Another important difference is in implementation. To be truly useful, COWL
> requires programmatic changes to an application to be data-flow aware since
> the policy is defined by the program itself. This includes making Labels to
> mark the integrity or confidentiality of data, as well as dropping
> privileges. Suborigins are applied declaratively in a header, and the
> policy lives fully in the header. This may require programmatic changes to
> the application, similar to moving an origin to a subdomain, but
> potentially few or no changes needed to the application, with the cost that
> it is a very coarse grained security mechanism.

It's true that if you wish to reap the benefits of labels you need to
modify your app to handle labeled data accordingly. But if your only
goal is to privilege separate applications, then the work should be the
same as Suborigins: you provide a header that specifies the initial
privilege of the context. One key difference is that COWL let's you
additional drop this privilege in JavaScript.
 

Deian

Received on Saturday, 23 January 2016 03:56:54 UTC