1. Introduction
This section is not normative.
Content Security Policy [CSP] defines a mechanism through which authors can manipulate the security properties of a given resource, providing the ability to mitigate the risk of a broad class of content-injection attacks. CSP, however, can only protect pages for which it is explicitly defined, which means that authors need to ensure that they’re delivering a reasonable policy for every page on their origin in order to have confidence that a particular set of restrictions will be consistently applied.
For example, it’s often the case that generic error-handling pages are constructed differently than "real" application pages. They’re easy to forget when auditing the security headers set for an origin, and can offer attackers a foot in the door if they contain injection vectors.
CSP Pinning attempts to address this concern by allowing authors to "pin" a
baseline policy to an application’s host. Conceptually, this is quite similar
to the approach taken by Strict Transport Security [RFC6797] and Public Key
Pinning [PKP]: we define a new header,
Content-Security-Policy-Pin
which instructs a user agent
to remember a baseline policy that will be enforced for any document and
worker delivered by an application that doesn’t come with its own
Content-Security-Policy
header.
1.1. Use Cases
example.com
has a number of applications running on the same
origin; each has a specific set of resources it needs to load, so a single
Content Security Policy would become unwieldy for the whole set of resources.
Moreover, the admins aren’t exactly sure they have a clear understanding of
all the applications running on subdomains; the marketing department went a
bit wild with branded partnerships a year or two back.
After doing an audit of existing code, they have a good feel for the needs of individual applications, and give each a suitable policy. They decide to err on the side of caution, and pin a restrictive policy for pages they didn’t catch:
https://example.com/application1/
delivers the following HTTP
response headers:
Content-Security-Policy-Pin: max-age: 10886400; includeSubDomains; default-src https:; form-action 'none'; frame-ancestors 'none'; referrer no-referrer; report-uri /csp-endpoint/pinned Content-Security-Policy: script-src https://application1.cdn.com; style-src https://application1.cdn.com; connect-src 'self'; form-action 'self'
While https://example.com/application2/
delivers the following
HTTP response headers:
Content-Security-Policy-Pin: max-age: 10886400; includeSubDomains; default-src https:; form-action 'none'; frame-ancestors 'none'; referrer no-referrer; report-uri /csp-endpoint/pinned Content-Security-Policy: script-src https://application2.cdn.com; style-src https://application2.cdn.com;
Meanwhile, they’ve forgotten about the coincidentally well-named
https://forgotten-partnership.example.com/
. It doesn’t send
any CSP headers at all, and yet, it is still protected by the pinned policy
for any users who have visited either Application 1 or Application 2.
2. Key Concepts and Terminology
2.1. Terms defined by this specification
- pinned security policy
- A security policy that is enforced for resources delivered from a protected host without their own policy. The pinned policy’s properties are defined in §3 Pinned Policy Delivery.
- pinned policy cache
-
In order to persistently enforce policy for an origin, the user
agent caches the following details about each pinned policy:
-
The protected host: a hostname to which the policy applies
(e.g.
example.com
) -
subdomains included:
true
ifincludeSubDomains
is asserted,false
otherwise. - The policy expiration date: the moment at which a pinned policy is no longer applicable
-
The policy directive set: a set of Content Security Policy
directives [CSP] that the user agent MUST apply, according to its
mode, for each
Document
andWorker
served from protected host, (and, potentially, its subdomains) that does not provide its own policy. -
mode:
monitor
if the policy directive set is to be monitored,enforce
if the policy directive set is to be enforced.
-
The protected host: a hostname to which the policy applies
(e.g.
The Augmented Backus-Naur Form (ABNF) notation used in §3 Pinned Policy Delivery is specified in RFC5234. [ABNF]
3. Pinned Policy Delivery
A server MAY instruct a user agent to pin a single security policy by
sending either a Content-Security-Policy-Pin
or
Content-Security-Policy-Report-Only-Pin
HTTP response
header field along with a resource. §4 Pinned Policy Processing defines the user
agent’s behavior when it receives such a response.
Once a policy is pinned, it will be either enforced or monitored as specified for any resource that doesn’t enforce or monitor its own policy.
Note: Pinned policies are delivered only via HTTP header fields; no meta element delivery mechanism is defined. Moreover, pinned policies override policies delivered via meta elements. See §7.2 Pins override <meta> for authoring guidelines.
3.1.
Content-Security-Policy-Pin
Header Field
The Content-Security-Policy-Pin
header field
is the mechanism for delivering a pinned policy that the user agent MUST
enforce for any resource which is not delivered with a
Content-Security-Policy
header (as described in the
§4.1.3
Pin a policy to response
algorithm.
The ABNF grammar is as follows:
"Content-Security-Policy-Pin:" 1#<policy-token production from CSP, Section 4.1>
Pinning a security policy is a somewhat dangerous operation, and
requires some reasonable expectation that the pinning is in fact desired by
a particular origin’s owner. To that end, a server MUST NOT send a
Content-Security-Policy-Pin
header with a
resource delivered from an a priori insecure
URL. The threat is discussed in more detail in §5.1 Hostile Pinning.
Note: This means that pinning is only practically available over HTTPS. This is intentional, as pinning is a "powerful feature" [POWER].
A server MUST NOT send more than one HTTP header field named
Content-Security-Policy-Pin
with a given resource
representation.
A server SHOULD send a Content-Security-Policy-Pin
with every
resource representation in order to ensure that pinning takes place
for a given user agent no matter how it accesses a site. The value of the
header SHOULD be the same for every resource representation, as the
goal is to enforce a consistent baseline policy for an entire set of hosts.
3.2.
Content-Security-Policy-Report-Only-Pin
Header Field
The Content-Security-Policy-Report-Only-Pin
header field is the mechanism for delivering a pinned policy that the user
agent MUST monitor for any resource which is not delivered with a
Content-Security-Policy-Report-Only
header (as described in the
§4.1.3
Pin a policy to response
algorithm).
The ABNF grammar is as follows:
"Content-Security-Policy-Report-Only-Pin:" 1#<policy-token production from CSP, Section 4.1>
As with Content-Security-Policy-Pin
, a server MUST NOT
send a Content-Security-Policy-Report-Only-Pin
header
with a resource delivered from an a priori
insecure URL. The threat is discussed in more detail in
§5.1 Hostile Pinning.
Note: This means that pin-reporting is only practically available over HTTPS. This is intentional, as pinning is a "powerful feature" [POWER].
A server MUST NOT send more than one HTTP header field named
Content-Security-Policy-Report-Only-Pin
with a given
resource representation.
A server SHOULD send a Content-Security-Policy-Report-Only-Pin
with every resource representation in order to ensure that pinning
takes place for a given user agent no matter how they access a site. The
value of the header SHOULD be the same for every resource
representation, as the goal is to monitor a consistent baseline policy
for an entire set of hosts.
What’s the impact of reporting? If headers can be injected into
appspot.com
or newyorktimes.com
, can attackers use
reporting to determine what apps you’re using, or what articles you’re
reading? Brian
has
explored this space a bit. Perhaps dropping reporting from pinned
policies would be reasonable. The main use-case I see would be discovering
pieces of your site that you haven’t covered with a policy (e.g. where did
the pin decrease attack surface?). It’s not clear we can even do that
without the implications Brian suggests.
3.3. Pinned Policy Syntax
The grammar for a pinned policy is the same as the grammar for the
Content-Security-Policy
header, defined in
Section 4.1 of the Content Security Policy
specification.
A pinned policy’s value MUST contain a max-age
directive, and MAY contain an includeSubDomains
directive.
3.3.1. The max-age
directive
The max-age
directive specifies the number of
seconds after the reception of the
Content-Security-Policy-Pin
HTTP response header
field during which the UA SHOULD enforce the pinned policy.
The directive is defined via the following ABNF grammar:
directive-name = "max-age" directive-value = 1*DIGIT
The max-age
directive MUST be present within the
Content-Security-Policy-Pin
header field. If it is not
present, the header field will be ignored (see §4 Pinned Policy Processing for
user agent requirements).
3.3.2.
The includeSubDomains
directive
The includeSubDomains
directive signals to
the user agent that the pinned policy defined in the
Content-Security-Policy-Pin
header field applies not
only to the origin that served the resource representation,
but also to any origin whose host component is a subdomain
of the host component of the resource representation’s
origin (see §4 Pinned Policy Processing for user agent requirements).
4. Pinned Policy Processing
The user agent discovers and processes pinned policies during fetching. Upon receiving a response, the user agent will:
-
Sift through the HTTP headers according to the §4.1.1 Discover pinned policies for response algorithm to determine if the pinned policy cache for the response’s host needs to be updated.
-
Update the pinned policy cache, according to the §4.1.2 Pin policy for origin in mode algorithm.
-
Update the response’s headers to ensure that any relevant pinned policies are applied, according to the §4.1.3 Pin a policy to response algorithm.
We probably need a hook in [Fetch]. In
particular, we need to ensure that we detect and pin a policy early enough
for frame-ancestors
and referrer
to handle blocking
and redirects.
Periodically, the user agent will run through the pinned policies it has stored in the pinned policy cache, and remove those that have expired, according to the §4.2.2 Remove expired pinned policies from the cache algorithm.
4.1. Fetching Algorithms
4.1.1. Discover pinned policies for response
Upon receiving a Response
response containing at least one
Content-Security-Policy-Pin
header field, the user agent
MUST peform the following steps:
- Let origin be the origin of response’s URL.
-
Let value be the result of parsing
Content-Security-Policy-Pin
in response’s header list. -
If value is not
null
, then execute the §4.1.2 Pin policy for origin in mode algorithm, passing in value, the origin of response’s URL, andenforce
. -
Let value be the result of parsing
Content-Security-Policy-Report-Only-Pin
in response’s header list. -
If value is not
null
, then execute the §4.1.2 Pin policy for origin in mode algorithm, passing in value, the origin of response’s URL, andmonitor
.
4.1.2. Pin policy for origin in mode
Given an Origin origin, a parsed set of directives
policy, and a mode (either enforce
or
monitor
), this algorithm defines the user agent behavior that
results in a pinned policy for origin.
- If origin is an a priori insecure origin, output a developer-friendly warning, and abort these steps.
- Let host be the host component of origin.
- If host is an IPv4 or IPv6 address, output a developer-friendly warning, and abort these steps.
- Let policy be the result of executing the parse the policy algorithm on directives.
-
If policy does not contain a
max-age
directive, then output a developer-friendly warning, and abort these steps. -
Let subdomains be
true
if anincludeSubDomains
is present in policy, andfalse
otherwise. -
Let TTL be the number of seconds specified in
policy’s
max-age
directive. If more than one such directive is present, let TTL be the largest value specified. - Let expiration be the current time, plus TTL.
-
Remove any
max-age
andincludeSubDomains
directives from policy. - Let pinned be the result of executing §4.2.1 Get the mode pinned policy for host for mode and host.
-
If pinned is not
null
, then update the pinned policy pinned as follows:-
If
max-age
is0
, then remove pinned from the pinned policy cache and abort these steps. -
Otherwise:
- Set pinned’s policy expiration date to expiration.
- Set pinned’s subdomains included to subdomains.
- Set pinned’s policy directive set to policy.
-
If
-
Otherwise, host is not a protected host. If
TTL is not
0
, then:- Let pinned be a new pinned policy.
- Set pinned’s protected host to host.
- Set pinned’s policy expiration date to expiration.
- Set pinned’s subdomains included to subdomains.
- Set pinned’s policy directive set to policy.
- Set pinned’s mode to mode.
- Add pinned to the pinned policy cache.
4.1.3. Pin a policy to response
Upon receiving a Response
response, ensure that it contains
appropriate Content-Security-Policy
headers by performing the
following steps:
- Let host be the host component of response’s URL’s origin.
-
Let pinned be the result of executing
§4.2.1
Get the mode pinned policy for host
for
enforce
and host. -
If pinned is not
null
:-
Let value be the result of
parsing
Content-Security-Policy
in response’s header list. -
If value is
null
:-
Append a header named
Content-Security-Policy
with a value of pinned’s policy directive set to response’s header list.
-
Append a header named
-
Let value be the result of
parsing
-
Let pinned be the result of executing
§4.2.1
Get the mode pinned policy for host
for
monitor
and host. -
If pinned is not
null
:-
Let value be the result of
parsing
Content-Security-Policy-Report-Only
in response’s header list. -
If value is
null
:-
Append a header named
Content-Security-Policy-Report-Only
with a value of pinned’s policy directive set to response’s header list.
-
Append a header named
-
Let value be the result of
parsing
4.2. Pinned Policy Cache Algorithms
4.2.1. Get the mode pinned policy for host
Given a host, and a mode mode, this algorithm
walks through the pinned policy cache, and returns the first matching
policy. If no policies match, this algorithm returns null
.
Note: There ought to be at most one policy that matches, given the constraints in §4.1.2 Pin policy for origin in mode .
-
For each policy in the pinned policy cache:
- If policy’s mode is not mode, skip to the next policy in the pinned policy cache.
- Let match type be the result of applying the Known HSTS Host domain name matching algorithm specified in [RFC6797] to host and policy’s protected host.
-
If match type is
Superdomain Match
, and policy’s subdomains included istrue
, then return policy. -
If match type is
Congruent Match
, then return policy.
-
Return
null
.
4.2.2. Remove expired pinned policies from the cache
Periodically, the user agent MUST remove expired policies from the pinned
policy cache. Removal will have no web-visible effect, as expired policies
will not modify Response
s during fetching, but expired policies can
have privacy impact if they aren’t removed completely (as they offer evidence
that a particular user visited a particular host at some point in the past).
Expired entries can be removed via the following steps:
-
For each policy in the list of pinned policies contained
in the pinned policy cache:
- If policy’s policy expiration date is prior to the current time, remove policy from the pinned policy cache.
5. Security Considerations
5.1. Hostile Pinning
An active network attacker who is able to inject headers into a site’s
responses may attempt to maliciously pin a security policy for a host
and its subdomains. Pinning default-src 'none'
on a page that
wasn’t built to work under such restrictions could deny service for an
entire application.
Unlike public key pinning [PKP], however, pinning a security policy cannot completely deny access to a site. This means that maliciously (or accidentally) pinned policies can be easily overridden in two ways:
-
Authors SHOULD send a valid security policy down with each HTTP
response, and use the pin only as a backup (see §7.1 Pins as a default).
Note: A future version of this specification may add a directive which prevents overriding the pinned policy (
no-override
?). This would allow authors to choose a stricter deployment model, but would remove this override possibility. -
Authors may also rescind a pinned policy by sending a new
Content-Security-Policy-Pin
header with amax-age
of0
.
Moreover, the risk of malicious injection is mitigated by the fact that we only accept pins over secure and authenticated connections.
6. Privacy Considerations
6.1. Fingerprinting
Similar to HSTS and HPKP, a pinned security policy could be used as a "supercookie", setting a distinct policy for each user which can be used as an identifier in combination with (or instead of) HTTP cookies.
For example, the report-uri
directive could contain a unique
identifier (report-uri https://example.com/endpoint?id=123
) which
could identify a user based on correlating violation reports with user
activity.
To mitigate this risk, user agents MUST:
- Clear the pinned policy cache when the user clears her browsing data (cookies, site data, history, etc).
-
Refuse to process
Set-Cookie
response headers during the send violation reports algorithm.
Can we assume that subdomains are really owned by the owner of the root domain?
7. Authoring Considerations
7.1. Pins as a default
Explain something about the theory; pins act as a baseline for resources that don’t otherwise have a policy. Explain layering, granularity, etc.
7.2. Pins override <meta>
Pinned policies are applied before meta elements can be
discovered. This means that a resource delivered without a header that
specified a security policy will be subject to the policy pinned
for its host, even if it then delivers a policy via the mechanisms described
in the HTML <meta>
element section of [CSP].
8. IANA Considerations
The permanent message header field registry should be updated with the following registrations: [RFC3864]
8.1. Content-Security-Policy-Pin
- Header field name
- Content-Security-Policy-Pin
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- This specification (See
Content-Security-Policy-Pin
Header Field)
8.2. Content-Security-Policy-Report-Only-Pin
- Header field name
- Content-Security-Policy-Report-Only-Pin
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- This specification (See
Content-Security-Policy-Report-Only-Pin
Header Field)
9. Acknowledgements
Yan Zhu kicked my butt to get this document out the door. I stole concepts wholesale from both HSTS and PKP.