1. Introduction
This section is not normative.
Modern Web applications are conglomerations of JavaScript written by multiple authors. Authors routinely incorporate third-party scripts into their applications and share user data with third-party services (e.g., as part of a mashup). Unfortunately, in the existing model, the user’s data confidentiality and integrity is put at risk when one incorporates untrusted third-party code or shares data with untrusted third-party services.
Mechanisms such as CORS and CSP can be used to mitigate these risks by giving authors control over whom they share data with. But, once data is shared, these mechanisms do not impose any restrictions on how the code that was granted access can further disseminate the data.
This document specifies an extension to the current model called
Confinement with Origin Web Labels (COWL). COWL provides authors
with APIs for specifying (mandatory) access control policies on
data, including content, in terms of origin labels. These
policies are enforced in a mandatory fashion, transitively, even
once code has access to the data. For example, with COWL, the
author of https://example.com
can specify that a
password is confidential to https://example.com
(and
thus should only be disclosed to https://example.com
)
before sharing it with a third-party password strength checking
service. In turn, COWL ensures that the third-party service, which
necessarily computes on the sensitive password, is confined and
respects the policy on the password: COWL disallows it from
disclosing the password to any origin other than https://example.com
.
COWL enforces such policies by confining code at the context-level, according to the sensitivity (i.e., the label) of the data the code has observed. To reap the greatest benefits of COWL, authors will need to compartmentalize applications into multiple contexts (e.g., iframes).
In the existing model, any page served from an origin has the
ambient, implicit authority of that origin. This documents
generalizes this notion of authority and gives authors explicit
control over it with privileges. For example, by default, a
page whose origin is https://example.com
has the
privilege for https://example.com
. This gives the page
the authority to arbitrarily disseminate data sensitive to https://example.com
; to be backwards-compatible,
the page is not confined when reading data sensitive to https://example.com
. However, COWL allows the author
to run the page with "weaker" delegated privileges (e.g., one
corresponding the current user at https://example.com
)
or to drop the privilege altogether.
COWL is intended to be used as a defense-in-depth mechanism that can restrict how untrusted—buggy but not malicious—code handles sensitive data. Given the complexities of browser implementations and presence of covert channels, malicious code may be able to exfiltrate data. Authors should still use discretionary access control mechanisms, such as CSP and CORS, to restrict access to the data in the first place.
1.1. Goals
The goal of COWL is to provide authors with a means for protecting
the confidentiality and integrity of data that is shared with
untrusted code, whether third-party or their own. Existing
mechanisms (e.g.,
CORS’s Access-Control-Allow-Origin
header and the targetOrigin
argument to postMessage()
) provide a way for restricting
which origins may access the shared data. But, once content
has access to data it can usually disseminate it without
restrictions. While CSP can be used to confine code, i.e., restrict
how confidential data is disseminated, setting a correct CSP policy
(as to confine code) is difficult and limited to content the author
has control over. Indeed, sharing confidential data in the existing
model almost always requires the sender to trust the receiver not to
leak the data, accidentally or otherwise. COWL provides a
defense-in-depth option for protecting data confidentiality and
integrity. In particular, with COWL:
-
Authors should be able to specify confidentiality and integrity policies on data in terms of origin labels: the origins to whom the data is confidential and the origins that endorse the data. This allows authors to share sensitive data with third-party content and impose restrictions on the origins with which it can communicate once it inspects the sensitive data. Dually, it allows authors to share data via intermediate content while retaining its integrity.
-
Authors should be able to run code with least privilege by restricting the origins the code can communicate with and thus how it can disseminate sensitive data.
-
Authors should be able to privilege separate applications by compartmentalizing them into separate contexts that have delegated privileges.
1.2. Use Cases/Examples
1.2.1. Confining untrusted third-party services
An author wishes to use a service, loaded in the form of an iframe, without trusting it (or its dependencies) to not leak her sensitive data. To protect the data, the author associates a confidentiality label with the data, specifying the origins allowed to read the data. The author then shares the newly created labeled object with the untrusted code. In turn, COWL confines the untrusted code once it inspects the sensitive data, as to ensure that it can only communicate according to the author-specified policy (the label).
https://example.com
wishes to use a third-party password strength checker provided by https://untrusted.com
. To protect the
confidentiality of the password, the https://example.com
application can use COWL to
associate a confidentiality policy, in the form of a label,
with the password before sending it to the untrusted service:
// Create new policy using Labels that specifies that the password is sensitive
// to https://example.com and should only be disclosed to this origin:
var policy = new Label(window.location.origin);
// Associate the label with the password:
var labeledPassword = new LabeledObject(password, {confidentiality: policy});
// Send the labeled password to the checker iframe:
checker.postMessage(labeledPassword, "https://untrusted.com");
// Register listener to receive a response from checker, etc.
Once the checker inspects the protected object, i.e., the
password, COWL limits the iframe to communicating with origins
that preserve the password’s confidentiality (in this case, https://example.com
). This policy is
enforced mandatorily, even if the https://untrusted.com
iframe sends the password to
yet another iframe.
Note, until the checker actually inspects the labeled password, it
can freely communicate with any origins, e.g., with https://untrusted.com
. This is important since the
checker may need to fetch resources (e.g., regular expressions) to
check the password strength. This is also safe—the checker has
not inspected the sensitive password, and thus need not be
confined.
Other use cases in this category include password managers and encrypted document editors, for example, where an encryption/decryption layer and a storage layer are provided by distrusting, but not malicious, services. The academic paper on COWL describes these use cases in detail [COWL-OSDI].
1.2.2. Sharing data with third-party mashups
A server operator wishes to provide third-party mashups access to
user data. In addition to using CORS response headers to restrict the origins that can access the data [CORS], the operator
wishes to restrict how the data is further disseminated by these
origins. To do so, the operator sends a response header
field named Sec-COWL
(described in §3.5.2 The Sec-COWL HTTP Response Header Field) whose value contains the
sensitivity of the data in the form of a serialized confidentiality label. In turn, COWL enforces the label restrictions on the
third-party code.
https://provider.com
uses a
CORS response header to grant https://mashup.com
access to a resource. The operator also sets a COWL header to
specify that the resource is confidential to https://provider.com
and should not be disseminated
arbitrarily:
Access-Control-Allow-Origin: https://mashup.com
Sec-COWL: data-confidentiality [ ["https://provider.com"] ]
COWL only allows a https://mashup.com
context to read
the sensitive response if the label restrictions of the response
are respected, i.e., if the code can only communicate with https://provider.com
.
Note, COWL only allows the code to inspect the response if the context labels, which dictate the context’s ability to communicate, are more restricting than the labels of the response. A more permissive approach, which does not require the context give up its ability to communicate arbitrarily is to use labeled JSON response. The mashup XHR example shows how authors can accomplish this.
1.2.3. Content isolation via privilege separation
A server operator wishes to isolate content (e.g., of different users) while serving it from a single physical origin. The operator can leverage privileges to ensure that content of one part of the site has different authority from another and, importantly, does not have authority of the physical origin. Concretely, when serving content, the operator can set the content’s context privilege to a weaker, delegated privilege. This ensures that the content are privilege separated.
https://university.edu
wished to isolate
different parts of their site according to users. The server
operator can weaken the privilege of a page when serving user
content by providing a response header field named Sec-COWL
(see §3.5.2 The Sec-COWL HTTP Response Header Field) whose value contains
a serialized delegated privilege. For example, for any
content under https://university.edu/~user1
, the
following header is set:
Sec-COWL: ctx-privilege [ ['self', 'cowl://user1'] ]
Having this privilege can be understood as having the authority of user1
’s part of the https://university.edu
origin. COWL ensures that the
content of this user cannot interfere with the content of https://university.edu
or another user
e.g., user2
. For example, the content cannot modify https://university.edu
cookies or the DOM of another http://university.edu
page.
This delegated privilege also ensures that the
content cannot disseminate data sensitive to another user (e.g., user2
) arbitrarily— without being confined,
it can only disseminate user1
’s data on http://university.edu
.
Of course, this requires the server operator to label
sensitive data (e.g., when sending it to the user agent) appropriately
(e.g., user2
’s data is labeled Label("https://university.edu")._or("user2")
).
The sub-origin isolation in JavaScript example shows how this can be implemented using the COWL JavaScript APIs.
1.2.4. Running content with least-privileges
An author wishes to use a library that is tightly coupled with the page (e.g., jQuery), but not trust it to protect the user’s confidentiality and integrity. With COWL, the author can do this by loading the untrusted library after dropping privileges (from the context’s default privilege). In doing so, the content (and thus the library) loses its implicit authority over the content’s origin.
https://example.com
can drop privileges
in JavaScript:
// Drop privileges, by setting the context privilege to an empty privilege:
COWL.privilege = new Privilege();
// Load untrusted library
Or, by setting the content’s initial privilege to the empty
privilege using Sec-COWL
response header:
Sec-COWL: ctx-privilege [ [] ]
In some cases it is useful for a particular context to have the
privilege to disseminate certain categories of data. (The or
part of labels can be used to easily
categorize differently-sensitive data.) To this end, the author
should run the context with a delegated privilege instead of
the empty privilege. The above §1.2.3 Content isolation via privilege separation shows
one such example.
1.3. Trust Model
COWL provides developers with a way of imposing restrictions on how untrusted code can disseminate sensitive data. However, authors should avoid sharing sensitive data with malicious code, since such code may be able to exploit covert channels, which are present in most browsers, to leak the data. COWL can only prevent information leakage from code that (e.g., is buggy and) uses overt communication channels.Similarly, COWL provides no guarantees against attacks wherein users are manipulated into leaking sensitive data via out-of-band channels. For example, an attacker may be able to convince a user to navigate their user agent to an attacker-owned origin by entering a URL that contains sensitive information into the user agent’s address bar.
sandbox
. 2. Key Concepts and Terminology
2.1. Labels
-
An origin label, or more succinctly a label, encodes either a confidentiality or integrity security policy as conjunctive normal form (AND’s and OR’s) formulae over origins. Labels can be associated with contexts or with structurally clonable objects.
When associated with a context, the label restricts the origins that the context can communicate with, as detailed in §3.3 Labeled Contexts.
The confidentiality labelLabel("https://a.com")._or("https://b.com")
, when associated with a context, restricts the context to sending data tohttps://a.com
orhttps://b.com
, but no other origins. This context label reflects the fact the context may contain data that is sensitive to eitherhttps://a.com
orhttps://b.com
; it is thus only safe for it to communicate to these origins.Note, because the context can communicate data to either origin, another context associated with the more restricting label
Label("https://a.com")
cannot send it data. Doing so would allow for data confidential tohttps://a.com
to be leaked tohttps://b.com
.The integrity labelLabel("https://a.com").or("https://b.com")
, when associated with a context, restricts the context to receiving data from (a context or server) that is at least as trustworthy ashttps://a.com
orhttps://b.com
. This context label ensures that the code running in the context can only be influenced by data which eitherhttps://a.com
orhttps://b.com
endorse.When associated with an object, a confidentiality label specifies the origins to whom the object is sensitive, while an integrity label specifies the origins that endorse the object. Objects that have labels associated with them are called labeled objects. §3.4 Labeled Objects defines how labels are associated with objects.
Consider anhttps://example.com
page that receives a labeled object (e.g., via postMessage()) with the following labels:-
Confidentiality:
Label("https://example.com")
. This label indicates that the object is sensitive tohttps://example.com
. -
Integrity:
Label("https://a.com")
. This label indicates that the object has been endorsed byhttps://a.com
. Ifhttps://example.com
received the message from an intermediaryhttps://b.com
context, this label reflects the fact that the object (produced byhttps://a.com
) was not tampered.
-
-
Mathematically, a label is a conjunctive normal form formula over origins [DCLabels].
A label is in normal form if reducing it according to the label normal form reduction algorithm produces the same value.
Two labels are equivalent if their normal form values are mathematically equal.
A label A subsumes (or is more restricting than) another label B if the result of running the label subsumption algorithm on the normal forms of A and B returns
true
. Labels are partially ordered according to this subsumes relation.The current confidentiality label is the confidentiality label associated with the current context. §3.3 Labeled Contexts specifies how labels are associated with contexts.
The current integrity label is the integrity label associated with the current context. §3.3 Labeled Contexts specifies how labels are associated with contexts.
When reading a labeled object, a context gets tainted, i.e., its context labels are updated by invoking context tainting algorithm, to reflect that it has read sensitive (of potentially different trustworthiness) data and should be confined accordingly.
2.2. Privileges
-
A privilege is an unforgeable object that corresponds to a label. Privileges are associated with contexts and reflect their authority.
Privileges can be used to bypass confinement restrictions imposed by confidentiality labels. In particular, a privilege can be used to bypass the restrictions imposed by any label its corresponding label—the internal privilege label—subsumes.
Consider a context fromhttps://a.com
whose current confidentiality label isLabel("https://a.com").and("https://b.com")
. This label confines the context to only communicating with entities whose labels are at least as restricting as this label. For example, it restricts the context from communicating with a context labeledLabel("https://b.com")
, since doing so could leakhttps://a.com
data tohttps://b.com
. It similarly prevents the context from communicating withhttps://a.com
.But, suppose that the context’s current privilege corresponds to
Label("https://a.com")
(afterall, the context originated fromhttps://a.com
). Then, the context would be able to bypass some of the restrictions imposed by the context label. Specifically, the context would be able to communicate withhttps://b.com
; the privilege confers it the right to declassifyhttps://a.com
data tohttps://b.com
. Indeed, when taking this privilege into consideration, the effective confidentiality label of the context isLabel("https://b.com")
.Note, the privilege does not allow the context to bypass any label restrictions. For example, it does not allow the context to communicate with
https://a.com
since doing so could leakhttps://b.com
data.To be flexible, COWL uses the context privilege to remove certain restrictions imposed by the context label. To avoid accidentally leaking sensitive context data, authors should use LabeledObjects.Privileges can also be used to bypass integrity restrictions imposed by integrity labels. In particular, a privilege can be used to endorse an otherwise untrustworthy labeled context (or labeled object) as to allow it to communicate with more trustworthy end-points (another context or server).
Consider anhttps://a.com
context whose current integrity label isLabel("https://a.com")._or("https://b.com")
. This label confines the context to only communicating with entities that are at most as trustworthy as this label. For example, it restricts the context from communicating with a context whose current integrity label isLabel("https://a.com")
, since doing so would potentially corrupthttps://a.com
data (e.g., by allowinghttps://b.com
to influence the computation).But, if the context’s current privilege corresponds to
Label("https://a.com")
, the context would be able to bypass some of these integrity restrictions. Specifically, the context would be able to communicate with the more-trustworthy context (labeledLabel("https://a.com")
) since the privilege confers it the right to endorse (or vouch for) its context on behalf ofhttps://a.com
. Indeed, when taking privileges into account, the effective integrity label of the context isLabel("https://a.com")
.Note, the privilege cannot be used to bypass any integrity restrictions. For example, it does not allow the context to communicate with a context whose integrity label is
Label(https://b.com)
.Note, browsing contexts have a current privilege that, by default, corresponds to the origin of the context, as described in §3.3 Labeled Contexts. But, authors should set the current privilege to a delegated privilege to follow the principle of least privilege.
-
The current privilege is the privilege associated with the current context. §3.3 Labeled Contexts specifies how privileges are associated with contexts.
-
The effective confidentiality label is the label returned by the label downgrade algorithm when invoked with the current confidentiality label and current privilege.
-
The effective integrity label is the label returned by the label upgrade algorithm when invoked with the current integrity label and current privilege.
-
Code can take ownership of a privilege priv by setting the current privilege to the privilege produced via the combination of the current privilege and priv. In doing so, it is said that the context owns the privilege.
3. Framework
This sub-section is not normative.
In a nut-shell, the COWL framework provides:
- Policy specification via origin labels
- COWL provides a Label interface for specifying
confidentiality and integrity policies in terms of origins. Labels can be associated with data and
content using the JavaScript LabeledObject and COWL interfaces or the
Sec-COWL
HTTP headers. - Explicit authority via privileges
- The COWL framework provides a JavaScript Privilege interface for operating on and minting
new privileges. The COWL JavaScript
interface and
Sec-COWL
HTTP response header can be used to explicitly control the authority of a context by setting the context privilege. - Confinement enforcement mechanism
- COWL extends browsing contexts and Workers with labels and privileges, which are used when enforcing confinement, i.e., when restricting a context’s network and cross-context messaging communication. This document defines the necessary changes and extensions to existing browser constructs and algorithms to enforce confinement.
3.1. Labels
Each label is an immutable object represented by a Label object, the interface of which is defined in this section.
A Label MUST have an internal label set, which is a non-empty set of disjunction sets.
A disjunction set is a set of origin URLs.
A label is said to be an empty label if its label set contains a single, empty disjunction set.
[Constructor, Constructor(DOMString origin), Exposed=Window, Worker] interface Label { boolean equals(Label other); boolean subsumes(Label other, optional Privilege priv); Label and((Label or DOMString) other); Label _or((Label or DOMString) other); object toJSON(); [Throws] static Label fromJSON(object obj, optional DOMString self); };
Current WebIDL implementation requires an underscore for
certain identifiers. Can we rename _or
to or
?
3.1.1. Constructors
- Label()
- When invoking the Label() constructor, the user agent MUST return a new empty label.
- Label(DOMString origin)
-
When invoking the Label(origin) constructor, the user agent
MUST use an algorithm equivalent to the following:
-
If the origin argument is not a URL, the constructor MUST throw a
TypeError
exception [ECMA-262] and terminate this algorithm. -
Else, it MUST return a new Label that contains a label set of a single disjunction set, which itself MUST contain the URL corresponding to the origin of the parameter.
-
3.1.2. Methods
- equals(Label other)
- The user agent MUST return
true
if the Label on which the method has been called is equivalent to the other parameter; otherwise it MUST returnfalse
. - subsumes(Label other, optional Privilege priv)
- The user agent MUST use an algorithm equivalent to the following:
- and((Label or DOMString) other)
-
The user agent MUST use an algorithm equivalent to the following:
-
Let O be the other argument.
-
If the type of other is
DOMString
, run the following sub-steps:-
Set O to the result of invoking the Label(other) constructor with other as an argument, if the constructor did not raise an exception.
-
Else, re-throw the exception and terminate this algorithm.
-
-
Return a new normal form Label that is equivalent to a label whose label set contains the disjunction sets of O and the Label on which the method was invoked.
-
- _or((Label or DOMString) other)
-
The user agent MUST use an algorithm equivalent to the following:
-
Let O be the other argument.
-
If the type of other is
DOMString
, run the following sub-steps:-
Set O to the result of invoking the Label(other) constructor with other as an argument, if the constructor did not raise an exception.
-
Else, re-throw the exception and terminate this algorithm.
-
-
Return a new Label, in normal form, which is equivalent to adding each element of each disjunction set of O’s label set to each disjunction set of the label set of the Label on which the method was called.
-
- toJSON()
-
The user agent MUST use an algorithm equivalent to the following:
-
Let JSON lset be a new JSON array.
-
For each disjunction set dset in the label set of the label, this method was invoked on:
-
Let JSON dset be a JSON array of strings, each corresponding to an origin in dset.
-
Append JSON dset to the JSON lset array.
-
-
Return JSON lset.
-
- fromJSON(obj, self)
-
The user agent MUST use an algorithm equivalent to the following:
-
If obj is not a JSON array of entries, each of which is a JSON array of strings, throw a
TypeError
exception [ECMA-262] and terminate this algorithm. -
Let self be null.
-
If the self argument is provided:
-
If the argument is not a URL, the function MUST throw a
TypeError
exception [ECMA-262] and terminate this algorithm. -
Else, set self to the self argument.
-
-
Let lab be a new empty label.
-
For each array element dset of obj:
-
Let dset label be a new empty label.
-
For each string str of dset:
-
If str is
"unique"
, let origin be a globally unique identifier.Much like FreshPrivilege(),"unique"
is used to create a label component that is globally unique. -
Else, if str is
"self"
and self is not null, let origin be self. -
Else, if str is a URL, let origin be str.
-
Else, throw a
TypeError
exception [ECMA-262] and terminate this algorithm. -
Let dset label be
dset label._or(origin)
-
-
Let lab be
lab.and(dset label)
-
-
3.1.3. Examples
// C: Public data.
// I: Non-endorsed/untrustworthy data.
var empty = new Label();
// C: Data confidential to a.com.
// I: Data endorsed/trusted by a.com.
var a = new Label("https://a.com");
// C: Data confidential to b.com.
// I: Data endorsed/trusted by b.com.
var a = new Label("https://b.com");
// C: Data confidential to both a.com and b.com
// I: Data endorsed/trusted by a.com and b.com.
var aANDb = new Label("https://a.com").and("https://b.com");
// C: Data confidential to either a.com or b.com.
// I: Data endorsed/trusted by either a.com or b.com.
var aORb = new Label("https://a.com")._or("https://b.com");
Examples of label comparisons with intuition for the semantics.
// C: Data confidential to a.com (b.com) data is more sensitive than public data.
// I: Data endorsed by a.com (b.com) is more trustworthy than non-endorsed/untrustworthy data.
a.subsumes(empty) === true;
b.subsumes(empty) === true;
// C: Data that is confidential to a.com and b.com is more
// confidential than data that is only sensitive to a.com (b.com).
// I: Data that is endorsed/trusted by both a.com and b.com is
// more trustworthy than data endorsed only by a.com (b.com).
aANDb.subsumes(a) === true;
aANDb.subsumes(b) === true;
// C: Data that that is confidential to a.com (b.com) is not comparable to
// data that is confidential to b.com (a.com).
// I: Data that that is endorsed by a.com (b.com) is not comparable to
// data that is endorsed by b.com (a.com).
a.subsumes(b) === false;
b.subsumes(a) === false;
// C: Data that is confidential to a.com (b.com) is more confidential than data that is
// confidential to either a.com or b.com. Alternative intuition: data that can be read by
// a.com or b.com can be read by an entity that can read a.com (b.com) data alone.
// I: Data that is endorsed by a.com (b.com) is more trustworthy than data that is endorsed
// by either a.com or b.com. Alternative intuition: an entity that trusts data endorsed
// by either a.com or b.com necessarily trusts data endorsed by a.com (b.com) alone.
a.subsumes(aOrb) === true;
b.subsumes(aOrb) === true;
var aORbANDc = aORb.and(new Label("https://c.com");
Converting to JSON:
JSON.stringify(empty) === '[[]]';
JSON.stringify(a) === '[["https://a.com"]]';
JSON.stringify(aANDb) === '[["https://a.com"], ["https://b.com"]]';
JSON.stringify(aORb) === '[["https://a.com", "https://b.com"]]';
JSON.stringify(aORbANDc) === '[["https://a.com", "https://b.com"], ["https://c.com"]]';
Converting from JSON:
Label.fromJSON([[]]).equals(empty) === true;
Label.fromJSON([["https://a.com"]]).equals(a) === true;
Label.fromJSON([["https://a.com"], ["https://b.com"]]).equals(aANDb) === true;
Label.fromJSON([["https://a.com", "https://b.com"]]).equals(aORb) === true;
Label.fromJSON([["https://a.com", "https://b.com"], ["https://c.com"]]).equals(aORbANDc) === true;
Label.fromJSON([["self"]], "https://a.com").equals(a) === true;
Label.fromJSON([["unique"]]).equals(Label.fromJSON([["unique"]])) === false;
3.2. Privileges
Each privilege is an immutable object represented by a Privilege object, the interface of which is defined in this section.
A Privilege MUST have an internal privilege label.
The combination of privileges A and B is a privilege produced by invoking the combine() method on A (respectively, B) with B (respectively, A) as an argument.
A privilege is said to be an empty privilege if its internal privilege label is the empty label. A context is said to be unprivileged if its context privilege is the empty privilege. By setting the context privilege to the empty privilege, a context is said to be dropping privileges.
A privilege P1 is said to be a delegated privilege of P2 if P2’s internal privilege label subsumes P1’s internal privilege label.
[Constructor, Exposed=Window, Worker] interface Privilege { static Privilege FreshPrivilege(); // Named constructor Label asLabel(); Privilege combine(Privilege other); [Throws] Privilege delegate(Label label); };
Bikeshed does not allow WebIDL’s NamedConstructor. For now, inlining the constructor as a static method.
3.2.1. Constructors
- Privilege()
- When invoking the Privilege() constructor, the user
agent MUST return a new Privilege that has an internal privilege label set to
Label()
. - FreshPrivilege()
-
When invoking the FreshPrivilege() constructor, the user agent MUST use an algorithm equivalent to the following:
-
Let unique Label be the label produced by invoking the Label(other) constructor with a globally unique identifier.
-
Return a new Privilege that has an internal privilege label set to unique Label.
-
3.2.2. Methods
- asLabel()
- The user agent MUST return the internal privilege label of the Privilege on which the method has been called.
- combine(Privilege other)
-
The user agent MUST return a new Privilege whose internal privilege label is equivalent to a label created according to an algorithm equivalent to the following:
-
Let internalLabel be the internal privilege label of the Privilege on which the method has been called.
-
Let otherLabel be the internal privilege label of the other argument.
-
Return
internalLabel.and(otherLabel)
.
-
- delegate(Label label)
-
The user agent MUST return a new Privilege whose internal privilege label is equivalent to a label created according to an algorithm equivalent to the following:
-
Let internalLabel be the internal privilege label of the Privilege on which the method has been called.
-
If the internalLabel does not subsume the label argument, throw a
SecurityError
exception and terminate this algorithm. -
Else, return a new Privilege that has an internal privilege label set to label.
-
3.2.3. Examples
https://example.com
has a privilege whose internal
privilege label is Label("https://example.com")
.
As a result, reading data that is sensitive to Label("https://example.com")
does
not confine the context. For example, reading a labeled object whose confidentiality label is Label("https://example.com")
does
not restrict the context from communicating—and thus
accidentally leaking that object’s contents—to another origin.
To prevent accidental leaks, the author should drop privileges by
setting the current privilege to an empty
privilege:
// Save privilege in case we need it later:
var __savedPriv = COWL.privilege;
// Drop privilege (set the context privilege to the empty privilege):
COWL.privilege = new Privilege();
After this point, if the context reads data with a Label("https://example.com")
confidentiality label, COWL will restrict it to communicating
with https://example.com
.
// Create new fresh privilege:
var priv = new FreshPrivilege();
// Take ownership of the fresh privilege:
COWL.privilege = COWL.privilege.combine(priv);
// Associate the unique label with the password:
var labeledPassword = new LabeledObject(password, {confidentiality: priv.asLabel()});
// Send the labeled password to the checker iframe:
checker.postMessage(labeledPassword, "https://untrusted.com");
Once the https://untrusted.com
context reads the
password it will be tainted by the unique, internal
privilege label of priv
; the unique origin
ensures that it cannot send the password to, for example, public
parts of https://example.com
. Indeed, only the
owner of priv
can disseminate the labeled password
(result) arbitrarily.
https://university.edu
isolates
different parts of their site according to
users. For user1
it can do this as follows:
// Create a label corresponding to the university origin:
var uni = new Label(window.location.origin);
// Create a new label that corresponds to user1’s data on university.edu:
var user1 = uni._or("cowl://user1"); // Here the cowl:// is an arbitrary scheme
// Originally, COWL.privilege.asLabel().equals(uni).
// Drop the current context privilege to a delegated privilege:
COWL.privilege = COWL.privilege.delegate(user1);
At this point, the context can only arbitrarily disseminate data
that is labeled Label("https://university.edu")._or("cowl://user1")
;
it cannot disseminate data that is
sensitive to the university (e.g., which is labeled Label("https://university.edu")
)
or to another user (e.g., user2
’s data is
labeled Label("https://university.edu")._or("cowl://user2")
).
3.3. Labeled Contexts
COWL extends browsing contexts and Workers with a COWL state, which is used to restrict the context’s communication channels. In this document, the term context is used to refer to both browsing contexts and Workers. The COWL state consists of:
-
The confinement mode status, which indicates whether or not COWL confinement is enabled and thus labels should be enforced in the current context.
-
The context labels, which consist of:
-
The context privilege, which encodes the context’s ability to bypass the restrictions of certain labels.
Each context’s COWL state MUST be initially set to the default COWL state, where:
-
The confinement mode is disabled.
-
The context confidentiality label is set to the default confidentiality label: empty label.
-
The context integrity label is set to the default integrity label: empty label.
-
The context privilege is set to the default privilege: a privilege whose internal privilege label is equivalent to Label(origin), where origin is the string representation of the context or Worker’s origin.
-
Unless confinement mode is enabled, a context is not subject to confinement.
-
Unless the current confidentiality label and the current integrity label are non-empty labels, the context’s communication is unrestricted; code is only subject to the restrictions imposed by other mechanisms such as the Same-Origin Policy and CSP.
-
Unless the current privilege is dropped or set to a delegated privilege, code can disseminate data sensitive to the browsing context’s origin, even when confinement mode is enabled. Such data is implicitly declassified using the context privilege. Authors should send LabeledObjects to explicitly communicate the sensitivity (and integrity) of the data they are sharing.
Each context’s COWL state is made available via the COWL interface defined below.
[Exposed=Window, Worker] interface COWL { static void enable(); static boolean isEnabled(); [SetterThrows] static attribute Label confidentiality; [SetterThrows] static attribute Label integrity; [SetterThrows] static attribute Privilege privilege; };
3.3.1. Attributes
- confidentiality, of type Label
-
-
On getting, the user agent MUST return the current confidentiality label.
-
On setting, the user agent MUST use an algorithm equivalent to the following:
-
Enable confinement mode.
-
Let conf be the set confidentiality label.
-
Let canWrite be the result of invoking the write check algorithm with conf and the current integrity label.
-
If canWrite is
false
, throw aSecurityError
exception and terminate this algorithm. -
Else, set the current confidentiality label to conf.
-
-
- integrity, of type Label
-
-
On getting, the user agent MUST return the current integrity label.
-
On setting, the user agent MUST use an algorithm equivalent to the following:
-
Enable confinement mode.
-
Let int be the set integrity label.
-
Let canWrite be the result of invoking the write check algorithm with the current confidentiality label and int.
-
If canWrite is
false
, throw aSecurityError
exception and terminate this algorithm. -
Else, set the current integrity label to int.
-
-
- privilege, of type Privilege
-
-
On getting, the user agent MUST return the current privilege.
-
On setting, the user agent MUST enable confinement mode and set the current privilege to the set privilege.
-
3.3.2. Methods
- enable()
- On invocation, the user agent MUST enable confinement mode by setting the current context’s COWL state confinement mode status.
- isEnabled()
- On invocation, the user agent MUST return
true
if the confinement mode is enabled for the current context; else, it MUST returnfalse
3.3.3. Examples
Below are several examples showing how to use the COWL API. The §3.2.3 Examples illustrate the use of context privileges.COWL.isEnabled() === false;
COWL.enable();
COWL.isEnabled() === true;
At this point, no confinement restrictions are applied—COWL is backwards compatible with the existing model. But, the context labels can be set to restrict communication.
COWL.integrity = new Label(window.location.origin);
https://mashup.com
can set the context
confidentiality label to receive data sensitive from https://provider.com
:
COWL.confidentiality = new Label('https://provider.com');
At this point, the context can only communicate with https://provider.com
. The data provider can
ensure that only appropriately labeled contexts
can inspect an HTTP response by setting response labels using
the Sec-COWL
response
header.
3.4. Labeled Objects
A LabeledObject interface represents an immutable object that is protected by a confidentiality and integrity label, i.e., the object has associated labels.
This API is designed to be used in conjunction with other APIs and
elements on the web platform. In particular, postMessage(), Web Workers, and XMLHttpRequest (e.g., with an
overloaded send()
method for LabeledObject arguments).
A LabeledObject MUST have an internal protected object, a confidentiality label, and an integrity label. The interface is defined below.
dictionary CILabel { Label? confidentiality; Label? integrity; }; [Constructor(object obj, CILabel labels), Exposed=Window, Worker] interface LabeledObject { readonly attribute Label confidentiality; readonly attribute Label integrity; [GetterThrows] readonly attribute object protectedObject; [Throws] LabeledObject clone(CILabel labels); };
3.4.1. Constructors
- LabeledObject(obj, labels)
-
When invoking the LabeledObject() constructor, the user agent MUST use an algorithm equivalent to the following:
-
Let obj clone be the result of obtaining a structured clone of the obj argument.
-
Let conf be the confidentiality member of the labels argument, if it is set. Otherwise, let conf be the current confidentiality label.
-
Let int be the integrity member of the labels parameter, if it is set. Otherwise, let int be the current integrity label.
-
Let canWrite be the result of invoking the write check algorithm with the conf and int labels.
-
If canWrite is
false
, the constructor MUST throw aSecurityError
exception and terminate this algorithm. -
Else, the user agent MUST return a new LabeledObject, with the protected object set to obj clone, the confidentiality label set to conf, and the integrity label set to int.
-
3.4.2. Attributes
- confidentiality, of type Label, readonly
- On getting, the user agent MUST return the LabeledObject’s confidentiality label.
- integrity, of type Label, readonly
- On getting, the user agent MUST return the LabeledObject’s integrity label.
- protectedObject, of type object, readonly
-
On getting, the user agent MUST use an algorithm equivalent to the following:
-
Invoke the context tainting algorithm with the LabeledObject’s confidentiality and integrity labels.
-
Return LabeledObject’s protected object.
-
-
The context can’t violate the confidentiality of the data (as specified by the confidentiality label) by communicating arbitrarily once it reads data labeled as such.
-
The context can’t violate the integrity of entities more trustworthy than the data. (The trustworthiness of the data is specified by the integrity label.) In particular, once the context reads the data and gets tainted, the rest of the computation is restricted to writing to entities that are at most as trustworthy as the data, since the read data may have influenced the computation.
3.4.3. Methods
- clone(CILabel labels)
-
On invocation, the user agent MUST use an algorithm equivalent to the following:
-
Let obj be the protected object of the object on which the method was invoked.
-
Let conf be the confidentiality label of the object on which the method was invoked.
-
Let int be the integrity label of the object on which the method was invoked.
-
Let newConf be the confidentiality member of the labels argument, if it is set. Otherwise, let newConf be conf.
-
Let newInt be the integrity member of the labels parameter, if it is set. Otherwise, let newInt be int.
-
Let privs be the internal privilege label of the current context privileges.
-
If
newConf.subsumes(conf, privs)
returnsfalse
or ifint.subsumes(newInt, privs)
returnsfalse
, the method MUST throw aSecurityError
exception and terminate this algorithm.Note, these checks ensure that the new labels of the object are at least as restricting as the original labels, taking into consideration the privileges of the context.
-
Else, return a new LabeledObject, with the protected object set to obj, the confidentiality label set to newConf, and the integrity label set to newInt.
-
3.4.4. Examples
Below are several examples showing the usage of LabeledObjects. §1.2.1 Confining untrusted third-party services gives an example of how LabeledObjects can be used to confine third-party libraries (e.g., a password strength checker). §3.6.1.1 Examples and §3.6.2.1 Examples show how LabeledObjects are used with the XMLHttpRequest constructor.https://police.gov
wishes to plot the
location of police cars on a map provided by https://maps.biz
without revealing the individual
car locations. After revealing the general area to https://maps.biz
, the author of https://police.gov
labels the police car
coordinates and sends them to the mapping service:
// Fetch map for provided location and draw it
mapsIframe.postMessage({ cmd: 'draw', location: ... }, mapsOrigin);
var locations = ... // Array of police-car coordinates
// Label the locations:
var labeledLocations = new LabeledObject(locations,
{ confidentiality: new Label(window.location.origin) });
// Send the labeled locations and plot them
mapsIframe.postMessage({ cmd: 'plot', locations: labeledLocations }, mapsOrigin);
When receiving a draw
message, the author of https://maps.biz
navigates the iframe map (a nested
context) to draw the map; otherwise, it simply forwards messages
from the parent (e.g., plot
, zoom
, and move
). (This design ensures that only the innermost
iframe gets tainted.)
The innermost map iframe registers a handler, that, for example, draws cars on top of map tiles:
window.addEventListener("message", function (event) {
switch (event.data.cmd) {
case 'plot':
var coordinates = event.data.locations.protectedObject;
coordinates.forEach(function (coordinate) {
// add car to map at coordinate
});
case 'zoom': ...
case 'move': ...
...
};
}, false);
Note that before getting the first protectedObject, the iframe
can communicate arbitrarily, e.g., to fetch map tiles. But once
it inspects the confidential locations COWL confines the
code—it restricts it to only communicating with https://police.gov
. Importantly, it can keep
receiving messages from its parent context via postMessage() to, for instance, move a car.
https://example.com
wishes to ensure
that a particular JSON object conforms to a set of validation
filters before submitting it to a remote server. (Consider, for
example, a form validator that checks if an email address is
valid.) To this end, it labels the JSON and sends the labeled
object to (e.g., a Worker or iframe) that performs the
validation.
The validation author inspects the object, but only endorses it if it conforms to the spec:
function handler(lObj) {
if (validateA(lObj.protectedObject)) {
var origin = ... ; // current origin (e.g., window.location.origin)
var endorsement = new Label(origin)._or('cowl://validate-A');
// Return a clone of the labeled object that is additionally
// endorsed by the current (sub-)origin.
return lObj.clone({ integrity: lObj.integrity.and(endorsement) });
} else {
return null;
}
}
The author of https://example.com
can then pass the
endorsed object to other validators or end-point (e.g., a
server), who can, in turn, further endorse the object or verify
the origins that have endorsed it.
3.5. The Sec-COWL
HTTP Headers
The Sec-COWL
HTTP request and response headers are
used by user agents and servers to convey label metadata to
servers and user agents, respectively.
Label metadata is either labeled context metadata or labeled data metadata.
Labeled context metadata encodes COWL state information, including:
-
the serialized context confidentiality label given by the ctx-confidentiality directive,
-
the serialized context integrity label given by the ctx-integrity directive, and
-
the serialized context privilege’s internal privilege label given by the ctx-privilege directive.
Its ABNF is:
ctx-metadata = ctx-directive *( ";" [ ctx-directive ] ) ctx-directive = *WSP ctx-directive-name 1*WSP label-set ctx-directive-name = "ctx-confidentiality" / "ctx-integrity" / "ctx-privilege"
Labeled data metadata is used to convey the confidentiality and integrity labels of an HTTP request or response, using the data-confidentiality and data-integrity directives. Its ABNF is:
data-metadata = data-directive *( ";" [ data-directive ] ) data-directive = *WSP data-directive-name 1*WSP label-set data-directive-name = "data-confidentiality" / "data-integrity"
The ABNF for serialized labels is:
label-set = "[" disjunction-set *( "," [ disjunction-set ] ) "]" / empty-label disjunction-set = "[" [ source-expression *( "," [ source-expression ] ) ] "]" source-expression = "'self'" / host-source empty-label = "[" *WSP "[" *WSP "]" *WSP "]"
The parsing algorithms for label metadata are given in §4.10 Parse labeled data metadata and §4.11 Parse labeled context metadata.
3.5.1. The Sec-COWL
HTTP Request Header Field
The ABNF for the Sec-COWL
HTTP request header is:
"Sec-COWL:" ( ctx-metadata [ "," data-metadata ] ) / ( data-metadata [ "," ctx-metadata ] )
The user agent MUST send a header field named Sec-COWL
along with requests if confinement mode is enabled.
The value of this header MUST contain the labeled context
metadata of the context that performed the request. This labeled context metadata MUST include the current context confidentiality label, context integrity
label, and context privileges. The user agent MAY
send another header with this field name whose value is labeled data metadata (e.g., when sending labeled
objects with XMLHttpRequest).
Note, according to [RFC2616], the user agent MAY combine multiple header field values into a single, comma-separated value.
http://a.com
page that has
read data sensitive to http://b.com
.
Sec-COWL: ctx-confidentiality [ ['https://b.com'] ];
ctx-integrity [ [] ];
ctx-privilege [ ['https://a.com'] ];
http://university.edu
context that owns a delegated privilege and a FreshPrivilege().
Sec-COWL: ctx-confidentiality [ [] ];
ctx-integrity [ [] ];
ctx-privilege [ ['http://university.edu', 'cowl://user1'], ['cowl://a0281e1f-8412-4068-a7ed-e3f234d7fd5a'] ];
When processing a request, a server SHOULD only use the first Sec-COWL
header that contains a ctx-metadata directive to retrive the labeled context metadata.
Similarly, a server SHOULD only use the first Sec-COWL
header that contains a data-metadata directive to retrive
the labeled data metadata of the request.
3.5.2. The Sec-COWL
HTTP Response Header Field
The ABNF for the Sec-COWL
HTTP response header is:
"Sec-COWL:" ctx-metadata / data-metadata
The header value may contain labeled context metadata which can be used to set the initial COWL state of a context; or it may contain labeled data metadata which specifies the sensitivity of the response (which COWL then uses to determine whether or not to block the response).
https://university.edu/~user1
page should run with
a delegated privilege—namely, Label("https://university.edu/")._or("cowl://user1")
—from
the start:
Sec-COWL: ctx-privilege [ ['self', 'cowl://user1'] ];
http://a.com
may wish to respond to a
request with data that is sensitive to both https://a.com
and https://b.com
, while simultaneously indicating that
it endorses the response data:
Sec-COWL: data-confidentiality [ ['https://a.com'], ['https://b.com'] ];
data-integrity [ ['https://a.com'] ];
COWL blocks the response unless the current context’s labels are at least as restricting.
To process this header, the user agent MUST use the Process response to request as COWL algorithm when performing a fetch, as described in §3.7.1 Modifications to Fetch.
3.6. Extensions to XMLHttpRequest
The XMLHttpRequest specification SHOULD contain the modifications described below to enable the rest of this specification’s work [XHR].
3.6.1. Sending labeled objects
To allow authors to send labeled objects to a remote server, this specification extends the XMLHttpRequest interface with an overloadedsend()
method:
partial interface XMLHttpRequest { void send(LabeledObject lobj); };
The send(lobj) method MUST use an algorithm that is equivalent to the following:
-
Let obj be the protected object of the lobj argument.
-
Let conf be the confidentiality label of the lobj argument.
-
Let int be the integrity label of the lobj argument.
-
Let privs be the current context privileges.
-
Let remoteConf be the label returned by the Label(origin) constructor called with the url associated with the request.
-
If
responseConf.subsumes(conf, privs)
returnsfalse
, throw aSecurityError
and terminate this algorithm.The user agent SHOULD warn the user that the script attempted to leak data to a remote server. -
Let json be a new JSON object with the following entries:
-
Set the
Content-Type
header to`application/labeled-json`
. -
Append a header named
Sec-COWL
to the author request headers associated with the object this methods was called on. The value of theSec-COWL
header MUST be labeled data metadata containing the confidentiality and integrity labels of the lobj argument. -
Invoke the
send()
method on the object this method was called on with json as an argument.Note, that
send()
throws an exception in step 4 if obj cannot be serialized. User agents MUST ensure that all protected objects can be serialized at the time of creating LabeledObjects.This algorithm does not check if the integrity label of the object subsumes the server’s integrity label. It is the server’s responsibility to ensure that untrustworthy data does not affect its computation in an unsafe way. Indeed, the only reason for checking the confidentiality labels is because the user agent has no way to ensure that the server will respect the confidentiality of the data.
3.6.1.1. Examples
https://example.com
sends JSON object
endorsed by https://validator.com
:
// Suppose that labeledObject is a public, high-integrity value:
JSON.stringify(labeledObject.confidentiality) === '[[]]';
JSON.stringify(labeledObject.integrity) === '[["https://validator.com"]]';
// Create an XHR request:
var req = new XMLHttpRequest()
req.open("POST", "https://example.com/...");
// Send the labeled object:
req.send(labeledObject);
Assuming the context has a default COWL state, send()
would send an HTTP request of the form:
Sec-COWL: ctx-confidentiality [[]];
ctx-integrity [[]];
ctx-privilege [["https://example.com"]];
Sec-COWL: data-confidentiality [[]];
data-integrity [["https://validator.com"]];
Content-Type: application/labeled-json;
{
"confidentiality": [[]],
"integrity": [["https://validator.com"]],
"object": ...
}
The server can then verify the integrity label of the request
and ensure that, if the user agent is conformant, the data was
endorsed by https://validator.com
.
3.6.2. Receiving labeled objects
To allow authors to receive labeled objects from remote servers, the XMLHttpRequest specification SHOULD contain the following modifications [XHR]:-
The
XMLHttpRequestResponseType
enumeration is extended with a new response type:enum XMLHttpRequestResponseType { // ... existing response types ... "labeled-json" };
-
The Response body section of the specification is modified to add:
-
An XMLHttpRequest has associated response LabeledObject object.
-
A labeled JSON response is the return value of these steps:
-
If the response LabeledObject object is non-null, return it.
-
If responseType is not
"labeled-json"
or the final MIME type is notapplication/labeled-json
, return null. -
If bytes is null, return null.
-
Let JSON text be the result of running utf-8 decode on byte stream bytes.
-
Let JSON object be the result of invoking the initial value of the
parse
property of theJSON
object, with JSON text as its only argument. If that threw an exception, return null. [ECMA-262] -
If the JSON object is missing any of the three entries:
"object"
,"confidentiality"
, or"integrity"
return null. -
Let protected object be the value of the
"object"
entry. -
Let conf be the label returned by calling the fromJSON() function with the
"confidentiality"
entry of the JSON object and self. If the function threw an exception, return null. -
Let int be the label returned by calling the fromJSON() function with the
"integrity"
entry of the JSON object and self. If the function threw an exception, return null. -
Let responseInt be the label returned by the Label(origin) constructor called with self.
-
If responseInt does not subsume int, return null.
Should the user agent warn the user if the server provided an integrity label that it is not allowed to provide?
-
Set the labeled JSON response to a newly created LabeledObject whose protected object is protected object, confidentiality label is conf, and integrity label is int.
-
Return the labeled JSON response.
-
-
-
Modify the response attribute by adding the following clause to step 2 of the ↪ Otherwise clause:
↪ If responseType is
"labeled-json"
Return the labeled JSON response.
-
Modify step 12 of the open() method by adding the following sub-step:
-
Set response LabeledObject object to null.
-
3.6.2.1. Examples
Specifically, the server operator of https://provider.com
uses a CORS response header to
send https://mashup.com
a labeled JSON object. To
ensure that the data is protected it sets the Content-Type
response header value to `application/labeled-json`
and sets the labels
appropriately:
Access-Control-Allow-Origin: https://mashup.com
Content-Type: application/labeled-json;
{
"confidentiality": [[]],
"integrity": [["https://provider.com"]],
"object": ...
}
The confidentiality label specifies that the object is
confidential to https://provider.com
and should
not be disseminated arbitrarily.
The author of https://mashup.com
can read such
labeled responses by simply setting the responseType accordingly:
// Create an XHR request to get the data:
var req = new XMLHttpRequest()
req.open("GET", "https://provider.com/apis/...");
req.responseType = "labeled-json";
req.onload = function (e) {
var labeledObject = req.response; // is a LabeledObject
// At this point, the context is still untainted, but:
JSON.stringify(labeledObject.confidentiality) === '[[]]';
JSON.stringify(labeledObject.integrity) === '[["https://provider.com"]]';
};
req.send();
Here, COWL sets the response to a new LabeledObject, but does not taint the
context with the response label. Indeed the https://mashup.com
integrator can perform many
other requests to different origins. Only when the protected objects of these labeled objects are
used will COWL taint the context and impose the label
restrictions.
Access-Control-Allow-Origin: *
Content-Type: application/labeled-json;
{
"confidentiality": [["'unique'"]],
"integrity": [[]],
"object": ... base64-encoded image ...
}
Once the receiver inspects the protectedObject of the response, COWL taints the context and ensures that it cannot communicate with anybody.
3.7. Confinement Enforcement
This sub-section is non-normative
To enforce confinement, COWL ensures that code in a context cannot send data (e.g., via cross-document messaging or by performing a fetch) to contexts or servers that do not preserve the confidentiality of the data. Similarly, COWL ensures that a context cannot receive data from a context or server that is less trustworthy.
3.7.1. Modifications to Fetch
The Fetch specification SHOULD contain the following modifications in order to enable the rest of this specification’s work [FETCH]:
-
Perform the following step between step 4 and 5 in the "main fetch" algorithm:
-
If should fetching request be blocked as COWL returns blocked, set response to a network error.
-
-
Perform the following step between step 12 and 13 in the "main fetch" algorithm:
-
If process response to request as COWL returns blocked, set response to a network error.
-
3.7.2. Modifications to Web Messaging
The Web Messaging specification SHOULD contain the following modifications in order to enable the rest of this specification’s work [WEBMESSAGING]:
-
Perform the following step between step 9 and 10 in the posting messages algorithm:
-
Let conf be the current context’s effective confidentiality label.
-
Let int be the current context’s effective integrity label.
-
Let dstState be the COWL state associated with the
Document
of theWindow
object on which the method was invoked. -
If confinement mode for dstState is enabled, let dstConf be the dstState effective confidentiality label.
-
Else, let dstConf be the Label returned by the label upgrade algorithm when invoked with the dstState context confidentiality label and context privilege.
Note, if the receiver has not enabled confinement mode, COWL flexibly assumes that it can receive data sensitive to its origin (in using the label upgrade).
-
Let dstInt be the dstState effective integrity label.
-
If dstConf does not subsume conf or if int does not subsume dstInt, then abort the remaining steps silently.
-
-
Perform the following step between step 9 and 10 in the MessagePort
postMessage()
method:-
Let conf be the current context’s effective confidentiality label.
-
Let int be the current context’s effective integrity label.
-
Let dstState be the COWL state associated with the owner of the target port the Message Port
postMessage()
was called on. -
If confinement mode for dstState is enabled, let dstConf be the dstState effective confidentiality label.
-
Else, let dstConf be the Label returned by the label upgrade algorithm when invoked with the dstState context confidentiality label and context privilege.
Note, if the receiver has not enabled confinement mode, COWL flexibly assumes that it can receive data sensitive to its origin (in using the label upgrade).
-
Let dstInt be the state effective integrity label.
-
If dstConf does not subsume conf or if int does not subsume dstInt, then abort the remaining steps.
-
3.7.3. Modifications to HTML5
When confinement mode is enabled the user agent MUST
ensure that content cannot access other content from the
same origin (e.g., using an iframe’s contentDocument
) that would violate
label restrictions. Specifically, if a browsing
context’s confinement mode is enabled
the user agent MUST set the following flags
of the context’s active sandboxing flag set:
If the context’s effective confidentiality label or integrity label are not the empty label, the user agent MUST additionally set the following flags:
-
The sandboxed origin browsing context flag. This flag ensures that the browsing context cannot access content of (what was previously) the same origin. It also prevents script from reading from or writing to the
document.cookie
IDL attribute, and blocks access tolocalStorage
. [WEBSTORAGE]The user agent MUST ensure that if content has access to another content from the same origin, but either ends up enabling confinement mode and has a non-empty label, access must be revoked and the two must be considered as if they are of different origins. Th current version of this document specifies this requirement in terms of the sandboxed origin browsing context flag.Implementation-wise, this may pose a challenge for certain browsers. An alternative design may disallow enabling confinement mode if the browsing context has any references to or from another same-origin content. Feedback on this would be very welcome.
Should COWL restrict communication via less overt
channels (e.g., height/width of an iframe, URL fragment, or
even)index in window.top.frames
)? Maybe as optional
modifications to HTML? Feedback on this would be very welcome.
4. Algorithms
4.1. Label Normal Form Reduction
The label normal form reduction algorithm takes a label argument and produces a Label value according to the following steps:-
Let lset be the label set of an empty label.
-
For each disjunction set dset in the label set of label:
-
If there is no disjunction set in lset that is a subset of dset, then:
-
Remove every disjunction set in lset that dset is a subset of.
-
Add dset to lset.
-
-
Note, this algorithms assumes that disjunction sets and label sets do not have duplicate elements, much like mathematical sets.
var a = Label("https://a.com"); // https://a.com
var aORb = Label("https://a.com")._or("https://b.com"); // https://a.com OR https://b.com
var a2 = a.and(aORb); // https://a.com AND (https://a.com OR https://b.com) ≡ https://a.com
The label a2
is equivalent to a
(since a.subsumes(aORb)
):
JSON.stringify(a2) === '[["https://a.com"]]';
a2.equals(a);
4.2. Label Subsumption
The label subsumption algorithm takes a two labels A and B and produces a boolean according to these steps:-
If, for each disjunction set b in the label set of B there is disjunction set a in the label set of A such that a is a subset of b, return
true
.
-
Else, return
false
.
Note, when interpreting labels as mathematical formulae, label subsumption is logical implication: A subsumes B is equivalent as A implies B, i.e, A⇒B.
4.3. Label Downgrade
The label downgrade algorithm takes a confidentiality label label and a privilege priv, and returns the least restricting label according to the following steps:-
Let privLabel be the internal privilege label of priv.
-
Let lset be the label set of an empty label.
-
For each disjunction set dset in the label set of label:
Note, label downgrade removes every disjunction set permitted by priv. This is used to safely declassify data labeled label.
4.4. Label Upgrade
The label upgrade algorithm takes an integrity label label and a privilege priv, and returns the most permissive label according to the following steps:-
Let privLabel be the internal privilege label of priv.
-
Return
label.and(privLabel)
.
Note, label upgrade is the dual of label downgrade. This can be used to safely endorse data labeled label (and thus potentially already endorsed).
4.5. Context Tainting
The context tainting algorithm takes a two labels, confidentiality and integrity, and updates the context labels to allow for reading data labeled with these labels. The user agent MUST use an algorithm whose behavior is as follows:-
Let currentConf be the current context confidentiality label.
-
Let currentInt be the current context integrity label.
-
Set the context confidentiality label to the Label returned by the by the label downgrade algorithm when invoked with currentConf.and(confidentiality) and current privilege.
-
Set the context integrity label to the Label returned by the by the label downgrade algorithm when invoked with currentInt._or(integrity) and current privilege.
4.6. Write Check
The write check algorithm takes two labels, objConf and objInt, and returnstrue
if the current context is allowed to write to
(or create) an entity labeled as such; otherwise, it returns false
. The user agent MUST use an algorithm whose
behavior is as follows:
-
Let currentConf be the current context’s effective confidentiality label.
-
Let currentInt be the current context’s effective integrity label.
-
If objConf does not subsume currentConf or if currentInt does not subsumes objInt, return
false
. -
Else, return
true
.
4.7. Structured Cloning
When a user agent is required to obtain a structured clone of an object whose type is defined in this document, it MUST use an algorithm whose behavior is as follows:-
Let input be the value being cloned.
-
If input is a Label object, let output be a newly constructed Label object with the same label set as that of input.
-
If input is a Privilege object that was constructed with the FreshPrivilege() constructor, let output be a newly constructed Privilege object with the same internal privilege label as that of input.
To prevent attacks that launder page privileges, the current version of COWL only allows transferring fresh privileges.We can be more permissive and allow transferring all but default privileges. Feedback on this would be welcome.
-
If input is a LabeledObject object, let output be a newly constructed LabeledObject object with the same internal protected object, confidentiality label, and integrity label as that of input.
-
Return output.
Note, cross-context messaging constructs such as postMessage() use the structured clone algorithm (e.g., see the internal structured cloning algorithm). This algorithm is used to allow authors to transfer COWL object, such as LabeledObjects, to other contexts.
4.8. Should fetching request be blocked as COWL?
Given a Request request, a user agent determines whether the Request request should proceed or not via the following algorithm:
-
Let context be the client associated with the request.
-
If context is null, let context be the incumbent settings object.
Note, the client associated with the request is null when navigating, so we use the incumbent settings object to get the COWL state of the context that initiated the request.
-
Let state be the COWL state retrieved via the environment settings object context.
-
If the state confinement mode is not enabled, return allowed and terminated this algorithm.
-
Let conf be the state effective confidentiality label.
-
Let dstConf be the Label created by invoking the Label(origin) constructor with the url associated with the request.
-
If dstConf subsumes conf, return allowed.
-
Else:
-
If the request is a navigation request and the context is a top-level browsing context, the user agent MAY return allowed, but MUST indicate to the user that data labeled conf may have been leaked due to the navigation. It is RECOMMENDED that user agents give users the options to block the navigation, e.g., via a pop-up dialog.
We can simply disallow leaks via top-level navigation at the cost of potentially forcing users to navigate away by closing tabs or inputting another URL via the address bar. Feedback on this would be welcome.
-
Else, return blocked.
-
Note, the integrity label of the current context is not used in
this algorithm since, conceptually, the integrity label of a
server is the empty label and, thus, always subsumed.
Server operators SHOULD check the Sec-COWL
request header
to ensure untrustworthy data does not affect the computation in an
unsafe way.
4.9. Process response to request as COWL
This algorithm is also used to set the COWL state for new documents and Workers according to server-supplied the labeled context metadata.
Given a Request request and Response response, a user agent determines whether the response should be returned via the following algorithm:
-
If the response’s header list has no header whose name is
Sec-COWL
, return allowed and terminate this algorithm. -
Let destination be the request’s destination.
-
Let type be the request’s type.
-
Let MIMEType be the result of extracting a MIME type from response’s header list.
-
Let context be the client associated with the request.
-
If context is null, let context be the incumbent settings object.
Note, the client associated with the request is null when navigating, so we use the incumbent settings object to get or set the COWL state of the context that initiated the request.
-
Let state be the COWL state retrieved via the environment settings object context.
-
Let metadata be the first header whose name is
Sec-COWL
in the response’s header list. -
If destination is
"document"
,"worker"
or"serviceworker"
:-
Let self be the serialization of the origin retrieved via the environment settings object context.
-
Let conf, int, priv be the result of calling the parse labeled context metadata algorithm with metadata and self.
-
If either conf, int, or priv are null, return blocked.
-
Else:
-
Set the state context confidentiality label to conf.
-
Set the state context integrity label to int, if the state effective integrity label subsumes int.
Note, by performing the label subsumption check before setting the context privilege (next step), the context integrity label can be upgraded from the empty label, while allowing the context privilege to also be dropped.
Should the user agent warn the user if the server provided an integrity label that it is not allowed to provide?
-
Set the state context privilege to priv, if priv is a delegated privilege of the state context privilege.
Should the user agent warn the user if the server provided a privilege that it is not allowed to provide?
-
Enable confinement mode for state.
-
Return allowed.
-
-
-
Else:
-
Let conf and int be the results of calling the parse labeled data metadata with metadata and self.
-
If either conf or int is null, return blocked and terminate this algorithm.
-
If the state effective confidentiality label subsumes conf and int subsumes the state effective integrity label, return allowed.
-
Else, return blocked.
Note, COWL conservatively blocks a response that is potentially more confidential or less trustworthy than the context making the request. In future versions of COWL, certain responses (e.g., images) which are only not as trustworthy as the context integrity label may be allowed by the user agent.
4.10. Parse labeled data metadata
To parse labeled data metadata metadata for origin self, the user agent MUST use an algorithm equivalent to the following:
-
Let conf be null.
-
Let int be null.
-
For each non-empty token returned by strictly splitting the string metadata on the character U+003B SEMICOLON (
;
):-
Collect a sequence of characters that are not space characters. The collected characters are the directive name.
-
If there are characters remaining in token, skip ahead exactly one character (which must be a space character).
-
The remaining characters in token (if any) are the directive value.
-
Let label value be the label returned by calling the fromJSON() function with the directive value and self. If the function threw an exception, ignore this instance of the directive and continue to the next token.
-
If directive name is
data-confidentiality
and conf is null, let conf be label value. -
Else, if directive name is
data-integrity
and int is null, let int be label value. -
Else, ignore this instance of the directive and continue to the next token.
-
Return conf and int.
4.11. Parse labeled context metadata
To parse labeled context metadata metadata for origin self, the user agent MUST use an algorithm equivalent to the following:
-
Let conf be null.
-
Let int be null.
-
Let priv be null.
-
For each non-empty token returned by strictly splitting the string metadata on the character U+003B SEMICOLON (
;
):-
Collect a sequence of characters that are not space characters. The collected characters are the directive name.
-
If there are characters remaining in token, skip ahead exactly one character (which must be a space character).
-
The remaining characters in token (if any) are the directive value.
-
Let label value be the label returned by calling the fromJSON() function with the directive value and self. If the function threw an exception, ignore this instance of the directive and continue to the next token.
-
If directive name is
ctx-confidentiality
and conf is null, let conf be label value. -
Else, if directive name is
ctx-integrity
and int is null, let int be label value. -
Else, if directive name is
ctx-privilege
and priv is null, let priv be a newly created privilege whose internal privilege label is set to label value. -
Else, ignore this instance of the directive and continue to the next token.
-
Return conf, int, and priv.
5. IANA Considerations
5.1. The Sec-COWL
HTTP Header Field
The permanent message header field registry should be updated with the
following registration [RFC3864]:
- Header field name
- Sec-COWL
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- This specification (See §3.5 The Sec-COWL HTTP Headers)
5.2. The application/labeled-json
MIME media type
- Type name
- application
- Subtype name
- labeled-json
- Required parameters
- Same as for
application/json
. [JSON] - Optional parameters
- Same as for
application/json
. [JSON] - Encoding considerations
- Same as for
application/json
. [JSON] - Security considerations
- Same as for
application/json
. [JSON] - Interoperability considerations
- Same as for
application/json
. [JSON] - Published specification
- Labeling a resource with the
application/labeled-json
type asserts that the resource is a JSON text that consists of an object with a single entry called"confidentiality"
consisting of an array of entries, each of which consists of an array of strings, a single entry called"integrity"
consisting of an array of entries, each of which consists of an array of strings, and a single entry called"object"
consisting of a JSON object. The relevant specifications are the JSON specification and this specification. [JSON] - Author/Change controller
- W3C
6. Acknowledgements
Thanks to Dan Boneh, Brendan Eich, Lon Ingram, Brad Hill, Dave Herman, Bobby Holley, Brad Karp, Jonathan Kingston, Petr Marchenko, David Mazières, Devon Rifkin, Alejandro Russo, and Brian Smith for influencing (directly or otherwise) the design of COWL and/or their comments on this document.