Security/CSP/Spec: Difference between revisions

From MozillaWiki
< Security‎ | CSP
Jump to navigation Jump to search
m (changed some instances of "request header" to "response header")
(→‎Policy Refinements with a META Tag: Clarified intersection description.)
Line 30: Line 30:


==Policy Refinements with a META Tag==
==Policy Refinements with a META Tag==
When both a <tt>X-Content-Security-Policy</tt> HTTP header <i>and</i> meta tag are present, the intersection of the two policies is enforced; essentially, the browser enforces the most relaxed policy satisfying both the policies specified in the meta tag and header.  The intersection is calculated on a directive-by-directive basis (i.e., the intersection of the <tt>allow</tt> directive is taken and enforced as the <tt>allow</tt> part of the effective policy).
When both a <tt>X-Content-Security-Policy</tt> HTTP header <i>and</i> meta tag are present, the intersection of the two policies is enforced; essentially, the browser enforces a policy that is more strict than both the policies specified in the meta tag and header, but only strict enough to correspond to rules in both policies.  Any web request that satisfied <i>both</i> policies alone will be accepted by the new policy, but any request rejected by <i>either one or both</i> of the two policies will be rejected.  The intersection is calculated on a directive-by-directive basis (i.e., the intersection of the <tt>allow</tt> directive is taken and enforced as the <tt>allow</tt> part of the effective policy). Explicitly:
 
<blockquote>
define R<sub>h</sub> &equiv; all URIs accepted by the HTTP header CSP<br/>
 
define R<sub>m</sub> &equiv; all URIs accepted by the meta tag CSP<br/>
 
 
R<sub>e</sub> = {r | r &isin; R<sub>h</sub> AND r &isin; R<sub>m</sub>}<br/>
 
(R<sub>e</sub> is the set of all URIs accepted by the intersected CSP)<br/>
</blockquote>


For example, the policy in the HTTP header (P<sub>header</sub>) may allow scripts from domains A, B and C.  The policy in the meta tag (P<sub>meta</sub>) may allow scripts from domains B, C and D.  The policy enforced (P<sub>enforced</sub>) by the browser will allow scripts from domains B and C only (P<sub>enforced</sub> = P<sub>header</sub> &cap; P<sub>meta</sub>).
For example, the policy in the HTTP header (P<sub>header</sub>) may allow scripts from domains A, B and C.  The policy in the meta tag (P<sub>meta</sub>) may allow scripts from domains B, C and D.  The policy enforced (P<sub>enforced</sub>) by the browser will allow scripts from domains B and C only (P<sub>enforced</sub> = P<sub>header</sub> &cap; P<sub>meta</sub>).

Revision as of 16:51, 6 April 2009

Specification

The purpose of this document is to provide a detailed description of how Content Security Policy definitions can be deployed. It explains the syntax for creating a CSP policy definition and how the defined policies are received and enforced by a user agent.

Background

Content Security Policy is intended to help web designers or server administrators specify how content interacts on their web sites. It helps mitigate and detect types of attacks such as XSS and data injection. CSP is not intended to be a main line of defense, but rather one of the many layers of security that can be employed to help secure a web site. More information about the intended use of CSP is available in the Overview section.

TODO: It is straightforward to convert a web site into one that can support CSP without loss of functionality. For more information, see Converting Your Site to CSP.

Terminology

A policy is composed of directives (such as "allow: none". Each directive is composed of a directive name and a directive value, which is either a list of host items or a URI (depending on the type of directive).

When CSP is activated for a site, a few refinements to the browser environment are made no matter the policy to help provide proper enforcement of any policy defined. These refinements provide general security enhancements by placing restrictions on the types of dynamic content that is allowed: generally any script on a site that converts text into code (through the use of eval() or similar functions) is disallowed. Details of the refinements can be found in the Refinements section.

Activation and Enforcement

CSP is activated by a client's browser when the X-Content-Security-Policy HTTP header is provided in a HTTP response (or when an equivalent meta tag is defined in the HTML document).

The Content Security Policy to be enforced can be delivered to the browser in one of two ways: directly as the value in the X-Content-Security-Policy HTTP header or a file served from the same host as the resource to be secured. The X-Content-Security-Policy header must either contain a policy definition or a policy-uri field; if both are present, the browser will raise a CSP console error and enforce the most restrictive ("allow none") policy.

If multiple X-Content-Security-Policy headers are present in the HTTP response, then the first one encountered is used and the rest are discarded.

The syntax is identical between file-based and header-based policy. The contents of a policy file are equivalent to the value of the X-Content-Security-Policy header. Authors who are unable to support signaling via HTTP headers can use <meta> tags with http-equiv="X-Content-Security-Policy" to define their policies.

HTTP Header Placement

The X-Content-Security-Policy HTTP Response header may be present anywhere in the response. Only the first one received by the user agent will be considered; any additional X-Content-Security-Policy HTTP Response headers in the same request will be ignored.

Meta Tag Placement

To minimize the chances of <meta>-tag injection, a CSP <meta> tag must be placed inside the <head> element of the protected HTML document. It must appear before any non-<meta> sibling tags, but can be preceded by any other <meta> tags.

Policy Refinements with a META Tag

When both a X-Content-Security-Policy HTTP header and meta tag are present, the intersection of the two policies is enforced; essentially, the browser enforces a policy that is more strict than both the policies specified in the meta tag and header, but only strict enough to correspond to rules in both policies. Any web request that satisfied both policies alone will be accepted by the new policy, but any request rejected by either one or both of the two policies will be rejected. The intersection is calculated on a directive-by-directive basis (i.e., the intersection of the allow directive is taken and enforced as the allow part of the effective policy). Explicitly:

define Rh ≡ all URIs accepted by the HTTP header CSP

define Rm ≡ all URIs accepted by the meta tag CSP


Re = {r | r ∈ Rh AND r ∈ Rm}

(Re is the set of all URIs accepted by the intersected CSP)

For example, the policy in the HTTP header (Pheader) may allow scripts from domains A, B and C. The policy in the meta tag (Pmeta) may allow scripts from domains B, C and D. The policy enforced (Penforced) by the browser will allow scripts from domains B and C only (Penforced = Pheader ∩ Pmeta).

Why Intersect Policies?

Because policy definitions are allowed both in the X-Content-Security-Policy header and in the Meta tag instances, it is possible they will both appear at the same time (and be different). A decision must be made about which policy to use, or whether to combine them or not. Assuming there are two different policies present, there are five obvious ways to address this conflict:

  1. Ignore both. Raise error in the console. Enforce "allow none" (most secure).
    Simplest and safest way to lock down when the policies conflict.
  2. Ignore both. Raise error in the console. Enforce "allow *" (most relaxed).
    This is a fail-open policy and will keep the site from breaking if two policies conflict.
  3. Use the HTTP Response header's policy.
    The argument for this resolution is that the lowest-level (HTTP) policy is most likely legit and the other is more likely script/data-injected; as a result, the safest policy should be trusted.
  4. Use the META tag's policy.
    One could consider the HTTP-Header policy a "global" policy and the META tag policy an exception. Most of the web site may follow the global policy, but the web programmers may want a different policy for a few of the pages on their server.
  5. Enforce the intersection of the policies.
    This is the technique used by CSP. For each URI that is accepted by both policies, the new intersected policy will also accept the URI. Any request that is not accepted by both policies will be rejected by the new policy.This provides the ability for interaction between the global-level (HTTP header) policy specification and one defined by the web programmers. Possibly, the sysadmin staff for a site may want to specify a base policy, but the code owners for a subset of the site may be interested in locking it down further. This technique allows the use of the META tag to make the global policy more restrict, but never more relaxed.

The fifth option, enforcing the intersection of the policies, is the best balance between safety and flexibility so CSP implements this conflict resolution technique. Furthermore, it is likely that those controlling the HTTP headers are not always the same people who maintain or create the web application itself -- the ability to "refine" or further restrict enforced policies allows the web programmers to tighten the belt on a CSP-protected page without violating the policy set out by the HTTP header (possibly set by the sysadmins).

Conflicting report-uri values

If both the HTTP header and meta tags define policies with report-uri values, a single report is sent to each of the provided URIs. If both report-uri values are the same, only one report for each violation is sent. If they are different, one report is sent to each unique URI.

Report-duplication (or dual reporting) is useful in the case where two different groups want to receive reports, but may not share access to the reports archive. Take for instance a large web company that has a separate sysadmin staff (who are also in charge of security at some level) and project teams. One project team may be interested in receiving reports about violations of their CSP, but are not interested in violations on other parts of the web site. The sysadmin team wants to record all violations from all parts of the site into a massive archive. The dual reporting technique allows both entities to receive the reports they want without causing extra data-mining work on the part of the sysadmin team to isolate the reports that each project team may want.

Data Leak Vectors

Since HTTP headers and the entire request string are sent in the report, it is possible that, if a META tag were injected, a violation report could leak private information to an arbitrary URI. To avoid any possible cross-domain cookie or authentication token transfer, all reports must be sent to the same host that served the protected content.

Policy Refinement Procedure

When a header and meta tag both present conflicting policies, they are resolved through a straightforward process: first the policies are made explicit (see below), then they are intersected, and the resulting policy is enforced. Through this process, the enforced policy will never be more lenient than either of the conflicting policies.

Policy Refinement Overview

This refinement procedure is only followed if there is a policy present in a HTTP header and there is one present in a META tag.

Making a Policy Explicit

The CSP policy language allows implicit values for directives through use of the "allow" (default) policy directive. To make a policy explicit, the policy language is "expanded", or any missing directives are added with the value specified in the "allow" directive. Once this expansion is complete, the allow directive is no longer necessary, and can be removed. In this way, an expanded policy never has the "allow" directive, but a declared (unexpanded) policy always has the "allow" directive.

Making a policy explicit

Intersecting Policies

The core of combining two policies is essentially the creation of a new policy where any valid request will also satisfy both original policies. In essence, if one HTTP request is allowed by both the Header-specified and Meta-Tag-specified policies, it will be allowed by the refined policy. If an HTTP request is disallowed by either specified policy it will be rejected by the refined policy.

Intersecting two explicit CSPs

In order to determine the intersection of two policies, the different directives are considered individually: for each directive in CSP, the values in both specified policies (A and B) are considered, and only those hosts allowed in both directive values are included in the intersection.

In order to determine the intersection of two policies, the different directives are considered individually: for each directive in CSP, the values in both specified policies (A and B) are considered, and only those hosts allowed in both directive values are included in the intersection.

Intersecting two directives

Policy Language and Syntax

A policy is composed of directives with their corresponding values. Any number of directives can be defined, but the allow directive must always be present. Each directive is followed with a list of host expressions except for policy-uri and report-uri which contain a single URI value. NOTE: In the case of policy refinemens as described above, it is possible to have two report-uri values; in this situation, a copy of the report is sent to each of the two URIs.

Directives

directive description
allow The catch-all section that defines the security policy for all types of content which are not called out in any of the other directives. This specifies the default for un-specified directives.
img-src Indicates which sources are valid for images. Images whose origin doesn't satisfy this directive will not be requested. Favicons are bound by this directive.
media-src Indicates which sources are valid for audio and video elements.
script-src Indicates which sources are valid for JavaScript. Only scripts loaded via the src= attribute will be loaded, and the src attribute's value must be indicated by this script-src directive.
object-src Indicates which sources are valid for object, embed, and applet elements.
frame-src Indicates which sources are valid for frame and iframe elements.
frame-ancestors Indicates which sources are valid ancestors for embedding the protected resource via frame and iframe tags. All web pages that are ancestors of the protected content must be indicated by the value of this directive. For example, if A embeds B which embeds C, and C defines a frame-ancestors as "B,C" then C is not rendered as a subframe.
style-src Indicates which sources are valid for stylesheets, including externally linked stylesheets, as well as inline <style> elements and style attributes of HTML elements.
report-uri Instructs the browser where to send a report when CSP is violated. The report will be an XML document sent via POST to the specified URI contained in the value of this directive. Report URIs must be on the same host as the protected content. Details are found in the Violation Report Syntax section.
policy-uri Indicates the location of a file containing the security policies for the protected resource. policy-uri should only be defined in the absence of other policy definitions in the X-Content-Security-Policy HTTP header. If policy-uri is defined among other directives in the header, a console error is raised and the policy enforced by CSP is the most restrictive policy: "allow none". Policy URIs must be on the same host as the protected content.

Host Expression List

Host expressions are a domain host name string that may contain wildcards. Examples of host expressions are "*.mozilla.com" and "mozilla.org". Internationalized domain names are specified according to their punycode representations.


Valid Host Expression Keywords

In place of host name expressions, these keywords can be used to specify classes of sources.

self
Refers to the host serving the protected content, including the scheme and port
none
Refers to the empty set (no hosts are valid)
data
Specifies data: URIs as valid resources

Formal Policy Syntax

<policy>            ::= <allow-directive><directive-list>

<allow-directive>   ::= allow <host-expr-list>

<directive-list>    ::= <empty> | <directives>";"<directive>

<directive>         ::= <host-directive>" "<host-dir-value>
                      | <uri-directive>" "<URI (RFC 2396)>

<host-directive>    ::= "img-src"
                      | "script-src"
                      | "object-src"
                      | "frame-src"
                      | "frame-ancestors"

<uri-directive>     ::= "report-uri"
                      | "policy-uri"

<host-dir-value>    ::= <source-list>
                      | "none"

<source-list>       ::= <source>
                      | <source-list>","<source>

<source>            ::= <scheme><host-name><port>
                      | "self"
                      | "data"
 
<scheme>            ::= <empty>
                      | <scheme-name>":"
                      | <scheme-name>":/"
                      | <scheme-name>"://"

<scheme-name>       ::= <alpha><scheme-suffix>

<host-name>         ::= "*" 
                      | <ldh-str>"."<ldh-str>
                      | <host-name>"."<ldh-str>

<port>              ::= <empty>
                      | ":"<integer>

<scheme-suffix>     ::= <scheme-chr> 
                      | <scheme-suffix><scheme-chr> 

<ldh-str>           ::= <let-dig-hyp>
                      | <ldh-symbol><let-dig-hyp>

<let-dig-hyp>       ::= <letter> | <digit> | "-"

<scheme-chr>        ::= <letter> | <digit> | "+" | "." | "-"

<letter>            ::= "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"
                      |"j"|"k"|"l"|"m"|"n"|"o"|"p"|"q"|"r"
                      |"s"|"t"|"u"|"v"|"w"|"x"|"y"|"z" 
                      |"A"|"B"|"C"|"D"|"E"|"F"|"G"|"H"|"I"
                      |"J"|"K"|"L"|"M"|"N"|"O"|"P"|"Q"|"R"
                      |"S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"

<integer>           ::= <digit> | <integer><digit> 

<digit>             ::= "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"0"

Sample Policy Definitions

Example 1: Site wants all content to come from its own domain:

X-Content-Security-Policy: allow self

or

<meta http-equiv="X-Content-Security-Policy" content="allow self" />

Example 2: Auction site wants to allow images from anywhere, plugin content from a list of trusted media providers, and scripts only from its server hosting sanitized JavaScript:

X-Content-Security-Policy: allow self; img-src *; \
                           object-src media1.com media2.com; \
                           script-src userscripts.example.com

or

<meta http-equiv="X-Content-Security-Policy" 
      content="allow self; img-src *; object-src media1.com media2.com; 
               script-src userscripts.example.com" />

Example 3: Server administrators want to deny all third-party scripts for the site, and a given project group also wants to disallow media from other sites (header provided by sysadmins and meta tag provided by project group are both present):

X-Content-Security-Policy: allow *; script-src self

and

<meta http-equiv="X-Content-Security-Policy" 
      content="allow *; script-src self; media-src self;" />

Violation Report Syntax

CSP supports a reporting mechanism that allows browsers to notify content providers when their policy is violated. When a report-uri is provided and a policy is violated, information about the protected resource and the violating content is transmitted to the report-uri. Such a report is an XML document containing the following fields:

request
HTTP request line of the resource whose policy is violated (including method, resource, path, HTTP version)
request-headers
HTTP request headers sent with the request (above) for the CSP-Protected content
blocked-uri
URI of the resource that was blocked from loading due to a violation in policy
violated-directive
The policy section that was violated (e.g., "script-src *.mozilla.org").

NOTE: in the case where a protected resource is not rendered because the frame-ancestors directive was violated, blocked-uri is not sent and is assumed to be the same as the request URI. The reason for this is because this situation is different from other policy violations: no third-party content was blocked, rather the protected content elected not to load since it does not trust the sites that have enframed it.

Violation Report XML Schema:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="csp-report">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="request" type="string" use="required" />
        <xs:element name="request-headers" type="string" use="required" />
        <xs:element name="blocked-uri" type="string" use="required" />
        <xs:element name="violated-directive" type="string" use="required" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>


Violation Report Sample

In this example, a page located at http://example.com/index.html was requested using HTTP 1.1 via the GET method. It provided a policy that included the directive "img-src self", which was violated by a request for some_image.png. The sample XML data sent to the policy-specified report-uri follows.

<csp-report>
  <request>GET /index.html HTTP/1.1</request>
  <request-headers>Host: example.com
           User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0
           Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  </request-headers>
  <blocked-uri>some_image.png</blocked-uri>
  <violated-directive>img-src self</violated-directive>
</csp-report>