Content Security Policy: Embedded Enforcement

W3C Working Draft,

This version:
https://www.w3.org/TR/2016/WD-csp-embedded-enforcement-20160909/
Latest published version:
https://www.w3.org/TR/csp-embedded-enforcement/
Editor's Draft:
https://w3c.github.io/webappsec-csp/embedded/
Previous Versions:
https://www.w3.org/TR/2015/WD-csp-embedded-enforcement-20151215/
Version History:
https://github.com/w3c/webappsec-csp/commits/master/embedded/index.src.html
Feedback:
public-webappsec@w3.org with subject line “[csp-embedded-enforcement] … message topic …” (archives)
Editor:
(Google Inc.)
Participate:
File an issue (open issues)

Abstract

This document defines a mechanism by which a web page can embed a nested browsing context if and only if it agrees to enforce a particular set of restrictions upon itself.

Status of this document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This document was published by the Web Application Security Working Group as a Working Draft. This document is intended to become a W3C Recommendation.

The (archived) public mailing list public-webappsec@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “csp-embedded-enforcement” in the subject, preferably like this: “[csp-embedded-enforcement] …summary of comment…

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by the Web Application Security Working Group.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 September 2015 W3C Process Document.

1. Introduction

This section is not normative.

Content Security Policy is a great defense against cross-site scripting attacks, allowing developers to harden their own sites against injection of malicious script, style, and other resource types. It does not, however, give developers the ability to apply restrictions to third-party content loaded in via <iframe>. Allowing CSP to apply directly to these third-party contexts would be dangerous; CSP gives quite granular control over resource loading, and it’s very possible to introduce vulnerabilities into an otherwise secure page by denying it access to particular scripts. We’ve seen these kinds of issues in past features such as X-XSS-Protection, so we must be careful to avoid reintroducing them in a new form.

That said, it would be quite useful to be able to place restrictions upon widgets, advertisements, and other kinds of third-party content. This document proposes a mechanism which relies on an explicit opt-in from the embedded content, which ought to make it possible for widgets to cooperate with their embedders to negotiate a reasonable set of restrictions.

In short, the embedder proposes a Content Security Policy as an attribute on the <iframe> element. This policy is transmitted along with the HTTP request for the framed content in an Embedding-CSP header. If the embedded content can accept that policy, it may do so by returning the proposed policy in a Content-Security-Policy header along with the response.

If the response contains a policy identical to the policy which the embedder requested, the user agent will render the embedded content. If no such policy is present, the response will be blocked.

1.1. Examples

MegaCorp Inc. wishes to ensure that the advertisements that run on its various publications are locked down to include script from trusted origins that have been audited for safety. They can do so by including the advertisement via an iframe element with a csp attribute:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm"
        csp="script-src https://trusted-cdn.example.com/">
</iframe>

This will generate a request to advertisements-r-us.example.com that has an Embedding-CSP header, as follows:

GET / HTTP/1.1
Host: advertisements-r-us.example.com
...
Embedding-CSP: script-src https://trusted-cdn.example.com/
...

The advertisement server parses this request header, decides that it’s acceptable, and reflects it in the response:

HTTP/1.1 200 OK
...
Content-Security-Policy: script-src https://trusted-cdn.example.com/

Since the policy asserted by the response matches the policy required by the request, the frame loads successfully.

The advertising server in the above example wishes to ensure that no plugins are loaded, regardless of what its embedder requires. It can do so by sending a restrictive policy in addition to any policy required by an embedder. That is, given a request that has an Embedding-CSP header:
GET / HTTP/1.1
Host: advertisements-r-us.example.com
...
Embedding-CSP: script-src https://trusted-cdn.example.com/
...

The advertisement server parses this request header, decides that it’s acceptable, and reflects it in the response, along with a policy that prevents plugin loading:

HTTP/1.1 200 OK
...
Content-Security-Policy: script-src https://trusted-cdn.example.com/,
                         object-src 'none'

The "," in the Content-Security-Policy header’s value splits the string into two serialized policies, each of which is enforced. The user agent verifies that one of the policies delivered with the response matches the requirement, and since additional policies can only make the effective policy for the page more restrictive, allows the frame to load successfully.

2. Framework

2.1. Integration with HTML

  1. iframe elements have a csp attribute which specifies the policy that an embedded document must agree to enforce upon itself. Valid attribute values match the serialized-policy grammar from [CSP3].

    partial interface HTMLIFrameElement {
      attribute DOMString csp;
    };
    

    HTMLIFrameElement's csp IDL attribute reflects the value of the element’s csp content attribute.

    Upstream this to all the HTMLs.

  2. A browsing context has a required CSP, which is either null or a serialized CSP. For a given browsing context (context), the value is the result of executing §3.3 Obtain the required CSP for context. on context.

    Does this need to be upstreamed? Probably not.

  3. Add the following to the list of error conditions in step 1 of HTML’s process a navigate response algorithm:

    Upstream this to WHATWG’s HTML.

    W3C’s HTML is not based on Fetch, and does not have a process a navigate response algorithm into which to hook. <https://github.com/w3c/html/issues/584>

  4. Add the following after step 5 of HTML’s process a navigate fetch algorithm:

    1. If browsingContext's required CSP is not null, append a header whose name is "Embedding-CSP" and whose value is browsingContext's required CSP to request's header list.

    Upstream this to WHATWG’s HTML.

    W3C’s HTML is not based on Fetch, and does not have a process a navigate fetch algorithm into which to hook. <https://github.com/w3c/html/issues/584>

2.2. The Embedding-CSP HTTP Request Header

In order to ensure that the embedded resource can decide whether or not it is willing to adhere to the embedder’s requirements, the policy expressed in an iframe's csp attribute is communicated along with some requests via an "Embedding-CSP" HTTP request header. The header’s value is represented by the following ABNF [RFC5234]:

Embedding-CSP = serialized-policy

A user agent MUST NOT send more than one HTTP response header field named "Embedding-CSP", and any such header MUST NOT contain more than one serialized-policy.

Servers MUST process only the first policy in the first such header received.

3. Algorithms

3.1. Is response blocked by context’s required CSP?

Given a response (response) and a browsing context (context), this algorithm returns "Allowed" or "Blocked" as appropriate:

  1. Return "Allowed" if either of the following is true:

    1. context is not a nested browsing context.

    2. context’s required CSP is null.

  2. Let embedding policy be the result of executing Content Security Policy Level 3 §parse-serialized-policy on context’s required CSP and "enforce".

  3. If response’s url’s scheme is a local scheme, or if response’s url’s origin is the same as the origin of the Document through which context is nested:

    1. Append embedding policy to response’s CSP list.

    2. Return "Allowed".

    Note: The embedder has direct access to same-origin responses, so if it wishes to enforce a policy on that same-origin response, we simply do so. Likewise, local scheme responses already inherit their policy from the embedder, so we allow the embedder to tighten that policy via this embedding mechanism.

  4. Assert: context is a nested browsing context, and response is a cross-origin, network schemed resource.

  5. If the §3.2 Is policy list subsumed under subsuming policy? algorithm returns "Subsumed" when executed upon response’s CSP list and embedding policy, return "Allowed".

  6. Return "Blocked".

3.2. Is policy list subsumed under subsuming policy?

Given a list of policy objects (policy list), this algorithm returns "Subsumed" if that list enforces a policy which is an exact match for a given policy object (subsuming policy). It returns "Not Subsumed" otherwise.

Note: Ideally, we’ll someday define a real subsumption algorithm which would verify that the policy default-src 'none'; script-src https://example.com is subsumbed under default-src example.com (as there is no case in which the latter will block a request that the former would allow). That calculation turns out to be hard, so the current algorithm takes the significantly simpler approach of requiring an exact match.

Note: This is not an efficient algorithm. Implementers are encouraged to implement something a little smarter and faster, with the same behavior.

  1. If subsuming policy is null, return "Subsumed".

  2. For each policy in policy list:

    1. If policy’s disposition is not "enforce", set skip to the next policy.

    2. If policy’s directive set is not the same size as subsuming policy’s directive set, skip to the next policy.

    3. For each directive in policy’s directive set:

      1. Let subsuming directive be the directive in subsuming policy’s directive set whose name matches directive’s name, or null if no such directive is present.

      2. If subsuming directive is null, skip to the next policy.

      3. If subsuming directive’s value list is not the same size as directive’s value list, skip to the next policy.

      4. For each token in directive’s value:

        1. If token is not present in subsuming directive’s value, skip to the next policy.

    4. Return "Subsumed".

  3. Return "Not Subsumed".

3.3. Obtain the required CSP for context.

Given a browsing context (context), the following algorithm returns its required CSP:

  1. If context is a nested browsing context.

    1. If context’s browsing context container has an csp content attribute, return its value.

  2. Return null.

4. Security and Privacy Considerations

4.1. Policy Enforcement

Embedded documents should be careful to evaluate the proposed Content Security Policy, and not simply to reflect whatever policy an embedder suggests. Doing so may enable a clever attacker to selectively disable pieces of a website’s code which are essential for its own protection.

In particular, documents which do not expect to be embedded should continue to respond to any such request with a Content Security Policy containing an appropriate frame-ancestors directive.

4.2. Policy Leakage

The enforcement mechanism allows a malicious embedder to read a page’s policy cross-origin by brute-forcing its constraints. This could leak interesting data about the page or the user loading the page if the policy contains secret tokens or usernames.

Again, the best defense here is to control the contexts allowed to embed a given resource via an appropriate frame-ancestors directive.

4.3. Data Exfiltration

This feature allows an embedder to send information to a third-party endpoint via the Embedding-CSP HTTP header. This doesn’t seem to expose any information that couldn’t be tunneled in the HTTP request itself (via GET parameters, etc), and embedders remain in control over the endpoints to which such requests may be made by enforcing a Content Security Policy with an appropriate child-src directive.

5. IANA Considerations

The permanent message header field registry should be updated with the following registration for the Embedding-CSP header: [RFC3864]

Header field name

Embedding-CSP

Applicable protocol

http

Status

standard

Author/Change controller

W3C

Specification document

This specification (See §2.2 The Embedding-CSP HTTP Request Header)

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSP3]
Mike West. Content Security Policy Level 3. 1 September 2016. WD. URL: https://www.w3.org/TR/CSP3/
[CSS-CASCADE-3]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 3. 19 May 2016. CR. URL: https://www.w3.org/TR/css-cascade-3/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. Registration Procedures for Message Header Fields. September 2004. Best Current Practice. URL: https://tools.ietf.org/html/rfc3864
[RFC5234]
D. Crocker, Ed.; P. Overell. Augmented BNF for Syntax Specifications: ABNF. January 2008. Internet Standard. URL: https://tools.ietf.org/html/rfc5234
[WHATWG-DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[WHATWG-URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

IDL Index

partial interface HTMLIFrameElement {
  attribute DOMString csp;
};

Issues Index

Upstream this to all the HTMLs.
Does this need to be upstreamed? Probably not.
Upstream this to WHATWG’s HTML.
W3C’s HTML is not based on Fetch, and does not have a process a navigate response algorithm into which to hook. <https://github.com/w3c/html/issues/584>
Upstream this to WHATWG’s HTML.
W3C’s HTML is not based on Fetch, and does not have a process a navigate fetch algorithm into which to hook. <https://github.com/w3c/html/issues/584>