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 by setting an attribute on an iframe
element. This policy is transmitted along with the HTTP request for the framed content in an
HTTP request header (Embedding-CSP
). If the embedded content can accept that
policy, it can enforce it by returning a Content-Security-Policy
or Allow-CSP-From
header along with the response.
If the response contains a policy at least as strict as the policy which the embedder requested, or accepts the embedder-provided policy, then the user agent will render the embedded content. If no such assertion is present, the response will be blocked.
1.1. Examples
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 adds a
header to the response, informing the user agent that it will adhere to the restrictions imposed
by its embedder (https://example.com
):
HTTP/1.1 200 OK ... Allow-CSP-From: https://example.com
Content-Security-Policy
header that’s at least as strong as the policy
which the embedder requires. For example, it might wish to ensure that no plugins are loaded,
regardless of what the embedder allows. It can do so by emitting a policy that includes the
embedder’s restrictions, and adds more on top:
HTTP/1.1 200 OK ... Content-Security-Policy: script-src https://trusted-cdn.example.com/; object-src 'none'
Since the policy asserted by the response allows strictly fewer requests than the policy required by the request, the frame loads successfully.
Note that the server could also deliver two policies, one which mirrors the restrictions of the embedder exactly, another which tightens them:
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
At a high level, this document describes a mechanism by which an embedee can opt-into a set of restrictions specified by its embedder. The mechanism involves a few steps:
-
The embedder specifies a required policy via a
csp
attribute on aniframe
element. This is described in more detail in §2.1 <iframe>'s csp attribute. -
That attribute’s value will be sent along with any navigation request that targets the
iframe
's nested browsing context in anEmbedding-CSP
HTTP request header. This header is described in more detail in §2.2 The Embedding-CSP HTTP Request Header.Rename this?
Required-CSP
, perhaps, to match the rest of the spec? -
The server can examine the
Embedding-CSP
header to determine whether it wishes to accept the required policy.If so, it can implicitly opt-in by sending aContent-Security-Policy
header in the response that contains a policy which is at least as strong as the required policy, or explicitly opt-in by sending anAllow-CSP-From
header in the response that enables the embedding origin to set whatever policy it wishes. The explicit mechanism is straightforward, described in §2.3 The Allow-CSP-From HTTP Response Header. The implicit mechanism is quite complicated, and comprises the entire §3 Implicit Policy Acceptance section.If the server doesn’t wish to accept the required policy, it can return an explicit error, or simply return the usual data without either a matching
Content-Security-Policy
header or anAllow-CSP-From
header. In this case, the user agent will block the response. This integration with HTML’s navigate algorithm is described in §2.4 Integration with HTML, and the blocking mechanism is spelled out in §4.1 Is response to request blocked by context’s required CSP?.
2.1. <iframe>
's csp
attribute
iframe
elements have a csp attribute, which specifies
the policy that an embedded document must agree to enforce upon itself. For example, the following
HTML would load https://embedee.example.com/
, and ensure that object-src 'none'
was enforced
upon it:
<iframe src="https://embedee.example.com/" csp="object-src 'none'"> </iframe>
A string (value) is a valid attribute value for a given element (element)'s csp
content attribute if all of the
following statements are true:
-
value is not the empty string.
-
value matches the serialized-policy ABNF grammar defined in [CSP3].
-
element’s node document’s browsing context’s required CSP is
null
, or the result of parsing value as "enforce
" is subsumed by element’s node document’s browsing context’s required CSP.
csp
attribute, as they’re valid CSP
grammar:
-
script-src 'none'
-
script-src 'self'; object-src 'none'; sandbox
-
not-a-directive https://whatever.not-a-tld
Note: We consider the last item valid even though it doesn’t express a meaningful policy in order to remain forward-compatible with future CSP syntax.
The following, on the other hand, do not match the CSP syntax, and would not be considered valid attribute values:
-
script-src *\nInjected-Header: XSS!
-
💩
Note: We need to be careful about the values we allow in the csp
attribute, as its
contents will end up reflected as an HTTP request header. This concern is discussed in a little
more detail in §5.4 Header Injection.
iframe
's csp
content attribute has a corresponding IDL attribute, defined
by the following WebIDL grammar [WEBIDL]:
partial interface HTMLIFrameElement { [CEReactions] attribute DOMString csp; };
HTMLIFrameElement
csp
IDL attribute’s getter will run the
following steps on a given element:
-
Let value be the value of element’s
csp
content attribute. -
If value is a valid attribute value for element, return value.
-
Return the empty string.
HTMLIFrameElement
csp
IDL attribute’s setter will run the
following steps on a given element for a given value:
-
If value is a valid attribute value for element, set element’s
csp
content attribute to the empty string and return. -
Set element’s
csp
content attribute to the empty string.
Upstream this to all the HTMLs.
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 affected navigation 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. As discussed in §5.5 Header Reflection, servers SHOULD also carefully consider the implications of simply
reflecting a policy back to a client. If the server wishes to simply accept an embedder’s
requirements, the Allow-CSP-From
header is a safer choice.
This header is set as part of HTML’s navigate algorithm (see §2.4 Integration with HTML for details on the hook that calls the following algorithm):
Embedding-CSP
header for a
given request (request), run the following steps:
-
If request is not a navigation request, return.
-
Let requirement be request’s client’s responsible browsing context’s required CSP.
-
If requirement is
null
, return. -
Assert: requirement is a serialized CSP, matching the serialized-policy grammar defined in [CSP3].
-
Append a header named "
Embedding-CSP
" with a value of requirement to request’s header list.
2.3. The Allow-CSP-From
HTTP Response Header
An embedee can opt-into accepting a policy specified by an embedder by responding with a
"Allow-CSP-From
" HTTP response header. The header’s value is
represented by the following ABNF [RFC5234]:
Allow-CSP-From = origin-or-null / wildcard
2.4. Integration with HTML
-
iframe
elements have acsp
attribute, defined in §2.1 <iframe>'s csp attribute. -
Each browsing context has a required CSP, defined in §2.4.1 Browsing Context’s Required CSP.
-
Add the following after step 10 of HTML’s navigate algorithm:
-
Set
browsingContext
's required CSP.
Upstream this to WHATWG’s HTML.
W3C’s HTML’s navigation algorithm is wildly divergent from WHATWG’s at this point. Upstream something to that document once things are reconciled. <https://github.com/w3c/html/issues/584>
-
-
Add the following to the list of error conditions in step 1 of HTML’s process a navigate response algorithm:
-
The §4.1 Is response to request blocked by context’s required CSP? algorithm returns "
Blocked
" when executed uponresponse
,request
, andbrowsingContext
.
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>
-
-
Add the following after step 5 of HTML’s process a navigate fetch algorithm:
-
Set
request
's "Embedding-CSP
" header.
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.4.1. Browsing Context’s Required CSP
Each browsing context has a required CSP, which is either null
or a serialized CSP. The value is set during the navigate algorithm, and will
not change until the browsing context’s active document changes.
The following algorithm will execute at around step 10 of the current navigate algorithm:
-
If context is a nested browsing context:
-
If context’s browsing context container has an
csp
content attribute with a valid attribute value (value), set context’s required CSP to value and return. -
Set context’s required CSP to the value of context’s parent browsing context’s required CSP.
-
-
Set context’s required CSP to
null
.
3. Implicit Policy Acceptance
An embedee can explicitly accept a policy requirement specified by its embedder by returning an Allow-CSP-From
header along with a response. The requirement can also be
implicitly accepted by delivering a Content-Security-Policy
header that
contains a policy (or set of policies) whose net effect is at least as strict as the policy
required by the embedder.
"At least as strict", however, isn’t very precise. Simple cases are straightforward: if an
embedder requires object-src https://cdn.example.com
, the embedee can respond with object-src 'none'
. Since every possible resource that would be blocked by the former would also be blocked
by the latter (because it allows no objects at all), we wouldn’t block the embedding. CSP’s
syntactical complexity makes this a little bit difficult to reason about for more complicated
cases. For instance, given script-src 'unsafe-inline' http: 'sha256-abc...def'
, it might appear
that script-src 'unsafe-inline'
would be a subset of the required policy. The presence of the hash-source expression, however means that 'unsafe-inline'
is ignored in the
required policy, so the latter policy would actually allow more than the former, despite
appearances.
To formalize the concept a bit, we need a few terms, and more than a few algorithms:
-
A policy (A) is said to subsume another policy (B) if B is at least as strict as A. In this case B could also be said to be subsumed by A. The details of determining "at least as strict"ness are spelled out in §3.2 Subsumption.
-
When multiple policies are present, they have a combined effect which is described in Content Security Policy Level 3 §multiple-policies. Here, we’ll talk about the combined effect of a list of policy objects as their intersection. The details of determining that are spelled out in §3.1 Intersection.
-
A policy (A) is said to subsume a list of policy objects if A subsumes their intersection.
3.1. Intersection
3.1.1. Policy List intersection
Note: It isn’t always possible to represent the intersection of multiple
policies as a single policy. Consider script-src 'unsafe-inline'
and script-src 'nonce-abc'
,
for instance: the former allows only inline script, the latter allows only inline or
externalized script with a particular token. The net effect (only inline script with a
particular token) cannot be created with a single policy. Dealing with such policies is, for the
moment, left as an exercise for the reader.
We shouldn’t make the reader do this exercise.
-
Let intersection be a policy object with an empty directive set and a disposition of "
enforce
". -
For each policy in policy list:
-
If policy’s disposition is "
report
", continue. -
Let result be the intersection of intersection and policy for origin
-
Set intersection to result.
-
-
Return intersection.
« "default-src 'self' http://example.com http://example.net; connect-src 'none';", "connect-src http://example.com/; script-src http://example.com/", "style-src 'self'; script-src http://example.com/ http://example.net", »
is the policy created by parsing the following serialized CSP:
"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/; style-src 'self'"
Each policy specified in the initial list subsumes the intersection.
3.1.2. Policy Intersection
-
Assert: A and B both have a disposition of "
enforce
". -
If A’s directive set is empty, return B.
-
If B’s directive set is empty, return A.
-
Let policy be a new policy with an empty directive set, and a disposition "
enforce
". -
Let directive names be an empty set.
-
For each directive in A:
-
For each directive in B:
-
For each directive name in directive names:
-
If directive name is "
report-uri
", "report-to
", continue. -
Let directive A be the effective directive value for directive name and A.
-
Let directive B be the effective directive value for directive name and B.
-
Assert: directive A and directive B are not both
null
, and either both of their values are source lists, or neither of their values are source lists. -
If either directive A or directive B has a value which is not a source list, continue.
We need to extend this definition to handle things that are not source lists. Also, we should be more precise about this, perhaps by defining a term like "source list directive" that we could check against directive name.
-
If directive A is
null
: -
If directive B is
null
: -
Let directive value be the intersection of directive A’s value, directive B’s value, directive name, and origin.
-
Let directive be a new directive with he following properties:
-
Append directive to policy’s directive set.
-
-
Return policy.
"default-src 'self' http://example.com http://example.net; connect-src 'none';" and "connect-src http://example.com/; script-src http://example.com/"
is the policy obtained by parsing the following serialized CSP:
"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/;
Both of the given policies subsume the intersection. For example,
the intersection’s "script-src http://example.com/
" is subsumed by the first policy’s "default-src 'self' http://example.com http://example.net
" and the second policy’s "script-src http://example.com/
".
3.1.3. Source List Intersection
https://example.com/
in A, and https://not-example.com/
in B), then the intersection will be the list
« 'none' ».
-
If directive A is not an ASCII case-insensitive match to directive B, return « 'none' ».
-
Let effective A be the effective source list for A, directive A, and origin.
-
Let effective B be the effective source list for B, directive B, and origin.
-
If either effective A or effective B is « 'none' », return « 'none' ».
-
If effective A is empty, return effective B.
-
If effective B is empty, return effective A.
-
Let schemes A and schemes be empty lists.
-
For each expression A in effective A:
-
If expression A matches
scheme-source
grammar:
-
-
For each expression B in effective B:
-
If expression B matches
scheme-source
grammar and expression B matches one of the elements in schemes A:
-
-
Let intersection be an empty source list.
-
For each expression in schemes:
-
For each expression A in effective A:
-
If expression A matches
scheme-source
grammar and schemes contains expression A, continue. -
Let match be
null
. -
For each expression B in effective B:
-
If at least one of expression A and expression B does not match
scheme-source
orhost-source
grammar:-
If expression A matches
keyword-source
grammar and is an ASCII case-insensitive match for expression B, append expression A to intersection. -
If expression A matches
nonce-source
orhash-source
grammar and is a case-sensitive match for expression B, append expression A to intersection. -
Continue to the next expression B.
-
-
If expression B’s
scheme-part
matches one of the elements in schemes, continue to the next expression B. -
If expression A matches
scheme-source
grammar:-
If expression B matches
host-source
grammar and the result of executing §4.2.2 What is an intersection of two expressions matching scheme-source or host-source grammar A and B? is notnull
given expression A and expression B, append the result to intersection. -
Continue to the next expression B.
-
-
If the result of executing §4.2.5 Does source list A subsume source listB given their respective origins and directive names? is "
Subsumes
" given expression B and expression A, append expression A to intersection. Continue to the next expression A. -
If the result of executing §4.2.2 What is an intersection of two expressions matching scheme-source or host-source grammar A and B? is not
null
given expression A and expression B, set match to the result.
-
-
If match is not
null
, append match to intersection.
-
-
Return intersection.
intersection
is an intersection for A and B.
A = wss: http://example.com B = https: wss: 'none' intersection = wss: https://example.com
The expression "wss:" is present in both policies, so it is present in their intersection. Similarly, "http://example.com" is present in the intersection because it is the only expression subsumed by both "http://example.com" and "https:". Note that "'none'"" is ignored, as it is not the only token in B.
A = http://*.a.com http://*.b.com B = https://a.com:* http://*.c.com intersection = https://a.com
Only two sources are similar: "http://*.a.com" in A is similar to "https://a.com:*" in B so the intersection of the two source lists is "https://a.com".
A = 'unsafe-inline' http://example.com:443/page1/html 'nonce-abc' B = 'unsafe-inline' https://example.com:443/ 'strict-dynamic' 'nonce-abc' intersection = 'nonce-abc'
Since "strict-dynamic
" honors only nonce-source
and hash-source
expressions, B is effectively
"'strict-dynamic' 'nonce-abc'". That is why the intersection is
"'nonce-abc'".
3.1.4. Intersection Helpers
3.1.4.1. Effective Directive Value
-
Switch on name and execute the associated steps:
-
"
child-src
""
connect-src
""
font-src
""
img-src
""
manifest-src
""
media-src
""
object-src
""
script-src
""
style-src
" -
"
frame-src
""
worker-src
" -
-
If policy’s directive set contains a directive whose name is name, return thatdirective’s value.
-
If policy’s directive set contains a directive whose name is "
child-src
", return thatdirective’s value. -
If policy’s directive set contains a directive whose name is "
default-src
", return thatdirective’s value. -
Return
null
.
-
-
"
base-uri
""
block-all-mixed-content
""
default-src
""
frame-ancestors
""
form-action
""
plugin-types
""
report-uri
""
require-sri-for
""
sandbox
""
upgrade-insecure-requests
"
-
-
Return
null
.
3.1.4.2. Effective Source List
'self'
and *
, and removes ineffective, obviated, or invalid
tokens (for instance, 'unsafe-inline'
in the presence of a nonce). The result
of running the following steps will generally be more verbose than list, but will be
significantly simpler to compare:
-
If list is empty or « 'none' », return « 'none' ».
-
If list contains the token "
'self'
":-
Remove that token from list.
-
Append the result of executing §4.2.3 Rewrite 'self' into a host-source expression for origin. given origin to list.
-
-
Let result be an empty source list.
-
For each expression in list:
-
If expression matches the
keyword-source
grammar, and name is not "script-src
" or "style-src
", continue. -
Continue if any of the following statements are true:
-
expression is "
'none'
" -
expression is "
'strict-dynamic'
" and name is not "script-src
" -
expression matches either the
nonce-source
orhash-source
grammar, and name is not "script-src
" or "style-src
" -
expression is "
'unsafe-inline'
", name is "script-src
, and list contains one or more tokens that match one of thenonce-source
grammar, thehash-source
grammar, or "'strict-dynamic'
" -
expression matches either the
host-source
orscheme-source
grammar, name is "script-src
", amd list contains the token "'strict-dynamic'
" -
name is "
plugin-types
", and expression does not match themedia-type
grammar
-
-
If expression is the U+002A ASTERISK character (
*
): -
Append expression to result.
-
-
If result is empty or « 'strict-dynamic' », return « 'none' ».
-
Return result.
For any directive with origin https://example.test/
:
https: wss: 'none' 'self'
The effective source list is "http: wss: https://example.test/". Note that "'none'" is not part of the effective source list because it has no effect when it is not the only source.
For "style-src
":
http://example.com 'strict-dynamic' 'nonce-abc'
The effective source list is "http://example.com 'nonce-abc'" since
"'strict-dynamic'" is ignored in non-"script-src
" directives.
For "script-src
":
http://example.com 'strict-dynamic' 'nonce-abc'
The effective source list is "'strict-dynamic' 'nonce-abc'" since
"'strict-dynamic'" in "script-src
" case does not honor host and scheme
source expressions.
Move the remaining intersection algorithms into this section.
3.2. Subsumption
4. Algorithms
4.1. Is response to request blocked by context’s required CSP?
Given a response (response), a request (request), and a browsing context (context), this algorithm returns "Allowed
" or
"Blocked
" as appropriate:
-
Return "
Allowed
" if either of the following is true:-
context is not a nested browsing context.
-
context’s required CSP is
null
.
-
-
Let embedding policy be the result of executing Content Security Policy Level 3 §parse-serialized-policy on context’s required CSP and "
enforce
". -
If the §4.2 Does response allow blanket enforcment of policy from request? algorithm returns "
Allowed
" when executed upon response and request:-
Append embedding policy to response’s CSP list.
-
Return "
Allowed
".
-
-
Assert: context is a nested browsing context, and response is a cross-origin, network schemed resource.
-
If the §4.3 Does subsuming policy subsume policy list given their respective origins? algorithm returns "
Subsumes
" when executed upon embedding policy, request’s origin, response’s CSP list, and response’s url’s origin, return "Allowed
". -
Return "
Blocked
".
4.2. Does response allow blanket enforcment of policy from request?
Given a response (response), and a request (request), this
algorithm returns "Allowed
" if the former allows the latter to enforce
arbitrary policy, and "Not Allowed
" otherwise:
-
If response’s url’s scheme is a local scheme, 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.
-
If response’s url’s origin is the same as request’s origin, return "
Allowed
".Note: Likewise, local scheme responses already inherit their policy from the embedder, so we allow the embedder to tighten that policy via this embedding mechanism.
-
If response’s header list has a header named
Allow-CSP-From
(header):-
If header’s value is "
*
", return "Allowed
". -
If request’s origin, serialized and UTF-8 encoded is header’s value, return "
Allowed
".
-
-
Return "
Not Allowed
".
4.2.1. Is an expression matching scheme-source
or host-source
grammar A similar to an expression matching scheme-source
or host-source
grammar B?
Given two expressions matching the scheme-source
or host-source
grammar (A and B), return "Similar
" if A is similar to B. Otherwise, return
"Not Similar
".
A and B are said to be similar if their
parts individually match, that is scheme-part
, host-part
, port-part
, and path-part
.
NOTE: This property is symmetric. That is if A is similar to B, it must be that B is similar to A.
A = https://inner.example.com/foo/ B = http://*.example.com/foo/bar/
Since A has a wildcard host, it matches any subdomain which in this case is "inner" so that A is similar to B.
A = http://*.example.com B = https://example.com:*
Even though A and B’s ports are different, A and B are similar because "http" matches both "http" and a more secure variant "https".
A = http://example.com:80/page1/html B = https://example.com:443/
In both sources specified ports are defalt ports for the respective schemes and B’s path would match any path, A is similar to B.
Cases when A is not similar to B.
A = http://example.com:80 B = http://example.com:334
In this case, ports of A and B do not match so that the two sources are not similar .
A = http://example.com/page.html B = http://example.com/index.html
The two sources are not similar beucase their paths do not match.
A source expression has a wildcard host if the first character of the source expression’s host-part
is an U+002A ASTERISK
character (*
).
A source expression has a wildcard port if the port-part
of the source expression is an U+002A
ASTERISK character (*
).
-
Let scheme A be A’s
scheme-part
, if present, andnull
otherwise. -
Let scheme B be B’s
scheme-part
, if present, andnull
otherwise. -
If the result of executing Content Security Policy Level 3 §match-schemes returns "
Does Not Match
" given scheme A and scheme B, and the result of executing Content Security Policy Level 3 §match-schemes on scheme B and scheme A is "Does Not Match
", return "Not Similar
". -
If A or B matches
scheme-source
grammar, return "Similar
". -
Return "
Not Similar
" if any of the following is true:-
Let host A be A’s
host-part
, if present, andnull
otherwise. -
Let host B be B’s
host-part
, if present, andnull
otherwise. -
Both A and B have a wildcard host, but host A is not an ASCII case-insensitive match to host B.
-
At most one of A and B has a wildcard host, the result of executing Content Security Policy Level 3 §match-hosts is "
Does Not Match
" given host A and host B, and the result of executing Content Security Policy Level 3 §match-hosts on host B and host A is also "Does Not Match
". -
Let port A be A’s
port-part
, if present, andnull
otherwise. -
Let port B be B’s
port-part
, if present, andnull
otherwise. -
Neither A nor B has a wildcard port, the result of executing Content Security Policy Level 3 §match-ports is "
Does Not Match
" given port A and port B, and the result of executing Content Security Policy Level 3 §match-ports given port B and port A is also "Does Not Match
". -
Let path A be A’s
path-part
, if present, andnull
otherwise. -
Let path B be B’s
path-part
, if present, andnull
otherwise. -
The result of executing Content Security Policy Level 3 §match-paths is "
Does Not Match
" given path A and path B and the result of executing Content Security Policy Level 3 §match-paths given path B and path A is also "Does Not Match
".
-
-
Return "
Similar
".
4.2.2. What is an intersection of two expressions matching scheme-source
or host-source
grammar A and B?
Source expression is said to be an intersection of two other
expressions matching scheme-source
or host-source
grammar A and B if it contains the more
restrictive scheme-part
, host-part
, port-part
, and path-part
of the two.
Intersect
is an intersection for A and B.
A = https: B = http: Intersect = https:
A = http://*.example.com B = https://example.com:* Intersect = https://example.com:443
A = http://example.com:80/page1/html B = https://example.com:443/ Intersect = https://example.com:443/page1/html
A = https:
B = http://example.com
Intersect = https://example.com
.
A = https://example.com:*
B = http://*.example.com/page.html
Intersect = https://example.com/page.html
Given two expressions matching the scheme-source
or host-source
grammar (A and B), return their intersection if A is similar to B. Otherwise, return null
.
-
If the result of executing §4.2.1 Is an expression matching scheme-source or host-source grammar A similar to an expression matching scheme-source or host-source grammar B? on A and B is "
Not Similar
", returnnull
. -
Let source be an empty string.
-
Let scheme A be A’s
scheme-part
, if present, andnull
otherwise. -
Let scheme B be B’s
scheme-part
, if present, andnull
otherwise. -
Let more secure scheme B be
true
if the result of executing Content Security Policy Level 3 §match-schemes is "Does Not match
" given scheme A and scheme B, andfalse
otherwise. -
Append scheme A and ":" to source if scheme A is not
null
and more secure scheme B isfalse
. Otherwise, append scheme B and ":" to source if scheme B is notnull
. -
If both A and B match the
scheme-source
grammar, return source. -
Append "//" to source if it is not empty.
-
Let host A be A’s
host-part
, if present, andnull
otherwise. -
Let host B be B’s
host-part
, if present, andnull
otherwise. -
If host A is not
null
:-
If host B is
null
, append host A to source. Continue to the next step in the main algorithm. -
If A doesn’t match the
scheme-source
grammar and doesn’t have a wildcard host, append host A to source. -
Otherwise, append host B to source.
-
-
If host A is
null
, append host B to source. -
Let port A be A’s
port-part
, if present, andnull
otherwise. -
Let port B be B’s
port-part
, if present, andnull
otherwise. -
If port A is
null
, append ":" and port B to source if it is notnull
. -
If port A is not
null
:-
If port B is
null
, append ":" and port A to source. Continue to the next step in the main algorithm. -
If A doesn’t have a wildcard port and more secure scheme B is
false
, append ":" and port A to source. -
Otherwise, append ":" and port B to source.
-
-
Let path A be A’s
path-part
, if present, andnull
otherwise. -
Let path B be B’s
path-part
, if present, andnull
otherwise. -
If path A is
null
, append path B to source if it is notnull
. -
If path A is not
null
:-
If path B is
null
, append path A to source. Continue to the next step in the main algorithm. -
If the result of executing Content Security Policy Level 3 §match-paths on path A and path B is "
Does Not Match
", append path A to source. -
Otherwise, append path B to source.
-
-
Return source.
4.2.3. Rewrite 'self'
into a host-source expression for origin.
Given an origin (origin), this algorithm returns a host-source
expression that has the same effect
as 'self'
for that origin:
-
If origin is an opaque origin, return the empty string.
-
Return the ASCII serialization of origin.
4.2.4. Does source expression
A subsume source expression
B?
Given two source expressions A and B, this algorithm returns
"Subsumes
" if A subsumes B, and returns
"Does Not Subsume
" otherwise.
-
Assert: Neither A nor B match the
keyword-source
grammar. -
If both A and B match either
host-source
orscheme-source
grammar:-
If Content Security Policy Level 3 §match-schemes returns "
Does Not Match
" given A’sscheme-part
(ornull
if A does not contain ascheme-part
) and B’sscheme-part
(ornull
if B does not contain ascheme-part
), return "Does Not Subsume
". -
If A or B matches the
scheme-source
grammar:-
If A matches the
scheme-source
grammar, return "Subsumes
". Otherwise, return "Does Not Subsume
".
-
-
If B has a
wildcard host
:-
If A doesn’t have a
wildcard host
, return "Does not Subsume
". -
Let remaining host B be the result of removing the leading ("*.") from B’s
host-part
. -
If Content Security Policy Level 3 §match-hosts returns "
Does Not Match
" given A’shost-part
and remaining host B, return "Does Not Subsume
".
-
-
If B doesn’t have a
wildcard host
and Content Security Policy Level 3 §match-hosts returns "Does Not Match
" given A’shost-part
and B’shost-part
, return "Does Not Subsume
". -
If A has a
wildcard port
but B doesn’t have awildcard port
, return "Does Not Subsume
". -
If A doesn’t have a
wildcard port
and Content Security Policy Level 3 §match-ports returns "Does Not Match
" given A’sport-part
(ornull
if A does not contain aport-part
) and B’sport-part
(ornull
if B does not contain aport-part
), return "Does Not Subsume
". -
If Content Security Policy Level 3 §match-paths returns "
Does Not Match
" given A’spath-part
(ornull
if A does not contain apath-part
) and B’spath-part
(ornull
if B does not contain apath-part
), return "Does Not Subsume
". -
Return "
Subsumes
".
-
-
If both A and B match the
hash-source
grammar:-
If A is a case-sensitive match to B, return "
Subsumes
". Otherwise, return "Does Not Subsume
".
-
-
If both A and B match the
nonce-source
grammar: -
Return "
Does Not Subsume
".
4.2.5. Does source list A subsume source listB given their respective origins and directive names?
Given a source list A with an origin (origin A) and a string (directive A), source list B with an origin (origin B) and a string (directive B), this
algorithm returns "Subsumes
" if A subsumes B, and
returns "Does Not Subsume
" otherwise.
A directive contains a given source expression if the expression is contained by its value.
-
If directive A is not an ASCII case-insensitive match to directive B, return "
Does Not Subsume
". -
If A is empty or B is
none
, return "Subsumes
". -
If B is empty or A is
none
, return "Does Not Subsume
". -
If directive B is "
script-src
" and B contains akeyword-source
expression "strict-dynamic
" but A does not contain it, return "Does Not Subsume
". -
If directive B is "
script-src
" or "style-src
":-
If B contains a
keyword-source
expression "unsafe-eval
" but A does not contain it, return "Does Not Subsume
". -
If B contains a
keyword-source
expression "unsafe-hashed-attributes
" but A does not contain it, return "Does Not Subsume
". -
Let type B be "
script
" if directive B is "script-src
" and "style
" otherwise. Similarly, let type A be "script
" if directive A is "script-src
" and "style
" otherwise. -
If Content Security Policy Level 3 §allow-all-inline returns "
Allows
" given B with type B, but returns "Does Not Allow
" given A with type A, return "Does Not Subsume
".
-
-
Let list A and list B be empty lists.
-
For each expression A in A:
-
If expression A is "
self
", append ahost-source
, returned by §4.2.3 Rewrite 'self' into a host-source expression for origin. given origin A to list A. -
If expression A matches the U+002A ASTERISK character (
*
), append to list A the followingscheme-source
expressions: "ftp:
", "http:
", "https:
", "ws:
", "wss:
", and origin A’s scheme.-
If directive A is either "
img-src
" or "media-src", append a <a grammar>
scheme-source</a> expression "
data:" to |list A|.</p> </li><li data-md><p>If |directive A| is "
media-src", append ascheme-source
expression "blob:
" to list A. -
Continue to the next expression A.
-
-
If expression A does not match
keyword-source
grammar, append expression A to list A.
-
-
For each expression B in B:
-
If expression B is "
self
", append ahost-source
, returned by §4.2.3 Rewrite 'self' into a host-source expression for origin. given origin B to list B. -
If expression B matches the U+002A ASTERISK character (
*
), append to list B the followingscheme-source
expressions: "ftp:
", "http:
", "https:
", "ws:
", "wss:
", and origin B’s scheme.-
If directive B is either "
img-src
" or "media-src", append a <a grammar>
scheme-source</a> expression "
data:" to |list B|.</p> </li><li data-md><p>If |directive B| is "
media-src", append ascheme-source
expression "blob:
" to list B. -
Continue to the next expression B.
-
-
If expression B does not match
keyword-source
grammar, append expression B to list B.
-
-
If list B is empty, return "
Subsumes
". -
If list A is empty, return "
Does Not Subsume
". -
For each expression B in list B:
-
If expression B matches the
hash-source
gramar, ornonce-source
grammar, continue to the next expression unless directive A is "script-src
" or "style-src
". -
Let found match be
false
. -
For each expression A in list A:
-
If §4.2.4 Does source expression A subsume source expression B? returns "
Subsumes
" given expression A and expression B, set found match totrue
. Break out of this inner loop.
-
-
If found match is
false
, return "Does Not Subsume
".
-
-
Return "
Subsumes
".
script-src
". Consider
the following examples:
A = "http://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com"
Since B does not allow hash-source
expressions, but its
value is found in A, A subsumes B. It is, however, not true that A subsumes B.
A = "https://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com"
In this case, A does not subsume B since "https://example.com" does not subsume "http://example.com".
A = "http://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com 'unsafe-inline'"
Since B allows all inline behavior, but A does not, A doesn’t subsume B.
A = "http://example.com 'sha256-xzi4zkCjuC8' 'strict-dynamic'" B = "http://example.com 'unsafe-inline' 'strict-dynamic'"
Neither A nor B allows all inline behavior. In this case, A subsumes B.
4.2.6. Does policy A subsume policy B given their respective origins?
Given a policy A with an origin (origin A) and a policy B with an origin (origin B), this algorithm returns "Subsumes
"
if A subsumes B, and returns "Does Not Subsume
"
otherwise.
-
If A’s directive set is empty, return "
Subsumes
". -
For each directive A in A’s directive set:
-
Let directive name be directive A’s name.
-
If directive name is "
default-src
", "report-uri
", "report-to
", continue. -
Let effective directive A be the effective directive value for directive name and A.
-
Let effective directive B be the effective directive value for directive name and B.
-
If effective directive A is
null
, continue. -
If effective directive B is
null
, return "Does Not Subsume
". -
If directive A’s name is "
frame-ancestors
": -
If directive A’s name is "
plugin-types
": -
If directive A’s name is "
sandbox
": -
Otherwise:
-
If the result of executing §4.2.5 Does source list A subsume source listB given their respective origins and directive names? is "
Does Not Subsume
" given effective directive A, origin A, directive name, effective directive B, origin B, and directive name, return "Does Not Subsume
".
-
-
Return "
Subsumes
".
-
4.3. Does subsuming policy subsume policy list given their respective origins?
Given a policy subsuming policy with an origin (subsuming origin) and a list of policy objects policy list with an origin (origin), this algorithm returns "Subsumes
"
if subsuming policy subsumes policy list, and returns
"Does Not Subsume
" otherwise.
-
If subsuming policy is
null
, return "Subsumes
". -
If subsuming policy’s disposition is "
report
", return "Subsumes
". -
If subsuming policy’s directive set is empty, return "
Subsumes
". -
If policy list is is empty or
null
, return "Does Not Subsume
". -
Let effective policy the result of executing §3.1.1 Policy List intersection given policy list and origin.
-
Return the result of executing §4.2.6 Does policy A subsume policy B given their respective origins? given subsuming policy, subsuming origin, effective policy, and origin.
5. Security and Privacy Considerations
5.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.
5.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.
5.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.4. Header Injection
Spell out the concerns Mario raised in the thread around https://twitter.com/0x6D6172696F/status/810066803653308416.
5.5. Header Reflection
Spell out the concerns Mario raised in the thread around https://twitter.com/0x6D6172696F/status/810066803653308416.
6. Authoring Considerations
6.1. Requiring 'self'
When processing a browsing context’s required CSP, the
keyword 'self'
refers to the origin of the URL being loaded
into the nested browsing context, not to the origin of the document in the source
browsing context.
'self'
on their page at https://example.com/page.html
:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm" csp="script-src 'self'"> </iframe>
If the returned CSP is:
Content-Security-Policy: script-src 'self'
Then this iframe
element will be loaded.
If, however, the returned CSP is:
Content-Security-Policy: script-src "https://example.com/"
Then this iframe
element will not be loaded.
7. 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)
Likewise, the registry should be updated with the following registration
for the Allow-CSP-From
header: [RFC3864]
-
Header field name
-
Allow-CSP-From
-
Applicable protocol
-
http
-
Status
-
standard
-
Author/Change controller
-
W3C
-
Specification document
-
This specification (See §2.3 The Allow-CSP-From HTTP Response Header)