1. Introduction
This section is not normative.
Increasingly, we encourage authors to transition their sites and applications away from insecure transport, and onto encrypted and authenticated connections [WEB-HTTPS]. While this migration has significant advantages for both authors and users, it isn’t without negative side-effects.
Most notably, mixed content checking [MIX] has the potential to cause real headache for administrators tasked with moving substantial amounts of legacy content onto HTTPS. In particular, going through old content and rewriting resource URLs manually is a huge undertaking. Moreover, it’s often the case that truly legacy content is difficult or impossible to update. Consider the BBC’s archived websites [BBC-ARCHIVE], or the New York Times' hard-coded URLs [NYT-HTTPS].
We should remove this burden from site authors by allowing them to assert to a user agent that they intend a site to load only secure resources, and that insecure URLs ought to be treated as though they had been replaced with equivalent secure URLs.
This document defines a new Content Security Policy directive, upgrade-insecure-requests
, through which authors can make
this assertion.
Note: Delivering the policy as a header allows an administrator to easily
opt a set of pages into the upgrade mechanism without touching their source
code individually. The legacy content examples above would not be feasible
with an approach that inlined the policy into HTML, for example.
1.1. Goals
The overarching goal is to reduce the burden of migrating websites from a priori insecure origins by reducing the negative side effects of mixed content blocking [MIX].
If we assume that authors do the server-side legwork (obtaining a certificate,
configuring the server, setting up redirects), and that authors also ensure
that both first- and third-party content is accessible at the same host
and path
on a secure scheme
, then the
following statements ought to hold after implementing this feature:
-
Authors should be able to ensure that all content requested by a given
page loads successfully, and securely. Mixed content blocking should not
break pages as a result of migrating to a secure origin.
Note: This requirement is not met by Mixed Content’s strict mode, which makes something like the opposite assertion.
- As a result of #1, the user agent should not degrade any security indicators related to requesting mixed content, as no insecure content should be requested.
- Authors should be able to ensure that all internal links correctly send users to the site’s secure address, and not to its pre-migration insecure address.
- Authors should be able to achieve all these goals without editing a site’s content. This is particularly important for archived content and legacy systems for which maintenance is difficult enough, never mind upgrades.
- Authors should be able to pursue a gradual transition from insecure to secure, serving secure resources to clients that support upgrades, while retaining insecure resources for clients that don’t.
Note: The mechanism defined here does not intend to supplant Strict Transport Security [RFC6797]. See §8.2 Relation to HSTS for details.
1.2. Examples
1.2.1. Non-navigational Upgrades
http://example.com/
to https://example.com
. They set up their servers
to make their own resources available over HTTPS, and work with partners in
order to make third-party widgets available securely as well.
They quickly realize, however, that the majority of their content is locked up in a database tied to an old content management system, and it contains hardcoded links to insecure resources (e.g., http:// URLs to images and other content). Unfortunately, it’s a substantial amount of work to update it.
As a stopgap measure, Megacorp injects the following header field into every HTML response that goes out from their servers:
Content-Security-Policy: upgrade-insecure-requests
This automatically upgrades all insecure resource requests from their pages to secure variants, allowing a user agent to treat the following HTML code:
<img src="http://example.com/image.png"> <img src="http://not-example.com/image.png">
as though it had been delivered as:
<img src="https://example.com/image.png"> <img src="https://not-example.com/image.png">
The URL will be rewritten before the request is made, meaning that no insecure requests will hit the network. Users will be safer, and Megacorp’s administrators will be happier, as all resource requests will be transparently upgraded with no effort on their part.
1.2.2. Navigational Upgrades
upgrade-insecure-requests
. That is, they’re already
delivering pages with the following header:
Content-Security-Policy: upgrade-insecure-requests
This allows user agents to treat the following HTML code:
<a href="http://example.com/">Home</a>
as though it had been delivered as:
<a href="https://example.com/">Home</a>
Links to third-party sites will not be upgraded. That is, the following HTML code:
<a href="http://not-example.com/">Home</a>
won’t be upgraded.
1.2.3. Failed Upgrade
upgrade-insecure-requests
a bit
earlier than they should have, as they don’t actually support HTTPS on http://cdn.example.com/
. Given the following code:
<img src="http://cdn.example.com/image.png">
User agents will upgrade requests, as described in §1.2.1 Non-navigational Upgrades,
rewriting the URL as https://cdn.example.com/image.png
. As the
server doesn’t respond to secure requests, this results in a network error.
There is no fallback in this scenario: the user agent acts just as though the request had been intentionally made, and the request fails.
1.3. Recommendations
We recommend that authors who wish to ensure that user agents which support upgrade-insecure-requests are as secure as possible do the following:
-
Redirect a priori insecure, safely upgradable
requests from HTTP to HTTPS by responding with a
Location
header and a307
status code. -
Respond to potentially secure safely upgradable requests with a
upgrade-insecure-requests
directive if necessary for the resource being requested.In Nginx, adding this directive might look like this:server { ... add_header Content-Security-Policy upgrade-insecure-requests; ... }
This is, of course, greatly simplified; your configuration will likely be significantly more complex.
-
If the origin is HSTS-safe, then protect
against SSL-stripping man-in-the-middle attacks by sending a
Strict-Transport-Security
header with thepreload
directive, and ensure that insecure content is never loaded by enabling Mixed Content’s strict mode.In Nginx, adding this header might look like this (note the use of thepreloaded
directive, which signifies that this origin’s HSTS state can be safely imported into user agents' HSTS preload lists):server { ... add_header Strict-Transport-Security "max-age=10886400; preload" add_header Content-Security-Policy block-all-mixed-content; ... }
This is, of course, greatly simplified; your configuration will likely be significantly more complex.
Additionally, work with user agent vendors to add the origin to HSTS Preload Lists (for example, by submitting the origin to hstspreload.appspot.com).
-
If the origin is conditionally HSTS-safe, then opt-into HSTS only
in response to safely upgradable requests.
In Nginx, adding this header conditionally might look like this (note the use of
map
, as setting headers insideif
without returning immediately is, well, iffy):server { ... map $http_https $sts { "1" "max-age=10886400" } add_header Strict-Transport-Security $sts; ... }
This is, of course, greatly simplified; your configuration will likely be significantly more complex.
2. Key Concepts and Terminology
-
A request is said to be upgraded if it is rewritten to contain a URL with a
scheme
ofhttps
orwss
. -
A request is said to be safely upgradable if the resource representation which will be returned does not require the
upgrade-insecure-requests
mechanism described in this document to avoid breakage, or if the request’s header-list contains anUpgrade-Insecure-Requests
header field with a value of1
. -
An origin is said to be HSTS-safe if no resource representations it returns requires the the
upgrade-insecure-requests
mechanism described in this document to avoid breakage, and if all resource representations it returns can be served over HTTPS.HSTS-safe origins can safely opt-into
Strict-Transport-Security
for all user agents, without risking broken pages for user agents which do not supportupgrade-insecure-requests
. -
An origin is said to be conditionally HSTS-safe if one or more resource representations it returns requires the
upgrade-insecure-requests
mechanism described in this document to avoid breakage, and if all resource representations it returns can be served over HTTPS.Conditionally HSTS-safe origins can safely opt-into
Strict-Transport-Security
only for user agents which supportupgrade-insecure-requests
. -
A
host
host is a preloadable HSTS host if, when performing Known HSTS Host Domain Name Matching, host is a superdomain match for a Known HSTS Host which asserts both the includeSubDomains directive and thepreload
directive, or host is a congruent matchfor a Known HSTS Host which asserts thepreload
directive.Note: This is a long way of saying "any host the user agent has pinned with a
Strict-Transport-Security
header that contained apreload
directive".
The Augmented Backus-Naur Form (ABNF) notation used in §3.1 The upgrade-insecure-requests Content Security Policy directive is specified in RFC5234. [ABNF]
3. Upgrading Insecure Resource Requests
In order to allow authors to mitigate the negative side-effects of migration away from a priori insecure origins, authors may instruct the user agent to transparently upgrade resource requests to potentially secure variants of the original request’s URL.
To support this instruction:
- Environment settings objects and browsing contexts are given an insecure requests policy which has two potential values Do Not Upgrade and Upgrade. It is set to Do Not Upgrade unless otherwise specified. This policy is checked in §4.1 Upgrade request to a potentially secure URL, if appropriate in order to determine whether or not non-navigation requests and form submissions should be upgraded during fetching.
- Environment settings objects and browsing contexts are
given an upgrade insecure navigations set which
contains a set of (
host
,port
) tuples to which navigations ought to be upgraded. Its value is the empty set unless otherwise specified. This set is checked in §4.1 Upgrade request to a potentially secure URL, if appropriate in order to determine whether or not navigation requests should be upgraded.
3.1. The upgrade-insecure-requests
Content Security Policy directive
A server MAY instruct a user agent to upgrade insecure requests for a
particular protected resource by sending a Content-Security-Policy
header [CSP] that contains a upgrade-insecure-requests directive, defined via the
following ABNF grammar:
directive-name = "upgrade-insecure-requests" directive-value = ""
When enforcing the upgrade-insecure-requests
directive:
- Let settings be the protected resource’s incumbent settings object.
- Set setting’s insecure requests policy to Upgrade.
- Let tuple be a tuple of the protected resource’s
URL
'shost
andport
. - Insert tuple into settings’s upgrade insecure navigations set.
Monitoring the upgrade-insecure-requests
directive has
no effect: the directive is ignored when sent via a Content-Security-Policy-Report-Only
header. Authors can
determine whether or not upgraded resources' original URLs
were insecure via Content-Security-Policy-Report-Only
. For
example, Content-Security-Policy-Report-Only:
default-src https:; report-uri /endpoint
. See §3.4 Reporting Upgrades for additional detail.
3.1.1. Relation to "Mixed Content"
The upgrade-insecure-requests
directive results in
requests being rewritten at the top of the Fetching algorithm [FETCH], as specified in §4.1 Upgrade request to a potentially secure URL, if appropriate. It’s important to note that
the rewrite happens before either Mixed Content [MIX] or Content
Security Policy checks take effect [CSP].
This ordering means that upgraded requests will not be flagged as
mixed content. Moreover, it means that upgrade-insecure-requests
’s effect takes place before
the block-all-mixed-content
directive would have a chance
to block the request. If the former is set, the latter is effectively a no-op.
We recommend that authors set one directive or the other, as outlined in §1.3 Recommendations.
3.2. Feature Detecting Clients Capable of Upgrading
Sites which require the upgrade mechanism laid out in this document in order
to provide users with a reasonable experience over secure transit need some
way to determine whether or not a particular request can safely be
redirected from HTTP to HTTPS (and vice-versa). Moreover, conditionally
HSTS-safe origins can only opt-into Strict-Transport-Security
for supported user agents, and
doing otherwise could have negative consequences for the site’s users.
Rather than relying on user-agent sniffing to make this decision, user agents
can advertise their upgrade capability when making navigation requests by including an Upgrade-Insecure-Requests
header field as
described in §3.2.1 The Upgrade-Insecure-Requests HTTP Request Header Field.
3.2.1. The Upgrade-Insecure-Requests
HTTP Request Header Field
The Upgrade-Insecure-Requests
HTTP request header
field sends a signal to the server expressing the client’s preference
for an encrypted and authenticated response, and that it can successfully
handle the upgrade-insecure-requests
directive in order
to make that preference as seamless as possible to provide.
This preference is represented by the following ANBF:
"Upgrade-Insecure-Requests:" *WSP "1" *WSP
Note: Though the Upgrade-Insecure-Requests
header expresses a
preference, sending it via the existing Prefer
header is
problematic, as we expect the response from the server to use it as part of
the cache key. Vary: Prefer
is too broad, as discussed in w3/webappsec#216.
User agent conformance details are described in step #1 of the the §4.1 Upgrade request to a potentially secure URL, if appropriate algorithm. That step represents the following requirements:
-
User agents MUST send an
Upgrade-Insecure-Requests
header field along with requests for a priori insecure URLs.Note: Servers can use this signal to upgrade HTTP requests to HTTPS for pages that require
upgrade-insecure-requests
support. -
User agents MUST send an
Upgrade-Insecure-Requests
header field along with requests for potentially secure URLs whose url’shost
is not a preloadable HSTS host.Note: Servers can use the absence of this signal to downgrade HTTPS requests to HTTP for pages that require
upgrade-insecure-requests
support. -
User agents SHOULD periodically send an
Upgrade-Insecure-Requests
header field along with requests for potentially secure URLs whose url’shost
is a preloadable HSTS host. For example, user agents could send anUpgrade-Insecure-Requests
header field only when the assertedmax-age
is a few days from expiration, or only for a small percentage of requests.Note: preloadable HSTS hosts have asserted that they are HSTS-safe, and therefore don’t need a downgrade signal. They will need to refresh HSTS status before the asserted
max-age
expires, and theUpgrade-Insecure-Requests
header field serves as a fine signal that HSTS could be refreshed.
When a server encounters this preference in an HTTP request’s headers, it SHOULD redirect the user to a potentially secure representation of the resource being requested.
When a server encounters this preference in an HTTPS request’s headers,
it SHOULD include a Strict-Transport-Security
header in
the response if the request’s host
is HSTS-safe or conditionally HSTS-safe [RFC6797].
http://example.com/
as follows:
GET / HTTP/1.1 Host: example.com Upgrade-Insecure-Requests: 1
The server parses the preference, notices that the user’s client can deal well with upgrade requests, and therefore responds to the request by redirecting the user to a secure version of the resource she’s requesting:
HTTP/1.1 307 Moved Temporarily Location: https://example.com/ Vary: Upgrade-Insecure-Requests
The Upgrade-Insecure-Requests
header field is listed in the Vary
header, as the
redirect response might otherwise be served by caches to clients that
don’t support the upgrade mechanism defined here. A similar effect could be
achieved by making this redirect response uncachable via the Cache-Control
header:
HTTP/1.1 307 Moved Temporarily Location: https://example.com/ Cache-Control: no-store
3.3. Policy Inheritance
If a Document
's incumbent settings object’s insecure requests
policy is set to Upgrade, the user agent MUST ensure that
all nested browsing contexts inherit the setting in the following ways:
-
When a nested browsing context context is created:
-
If context’s embedding document’s insecure
requests policy is Upgrade, then:
- Set context’s insecure requests policy to Upgrade.
- For each value in context’s embedding document’s upgrade insecure navigations set, add value to context’s upgrade insecure navigations set.
-
If context’s embedding document’s insecure
requests policy is Upgrade, then:
-
When creating a new
Document
object document in a browsing context context:-
If context’s insecure requests policy is Upgrade, then:
- Let settings be document’s incumbent settings object.
- Set settings' insecure requests policy to Upgrade.
- For each value in context’s upgrade insecure navigations set, add value to settings’s upgrade insecure navigations set.
-
If context’s insecure requests policy is Upgrade, then:
Likewise, when spinning up a worker, the user agent MUST ensure that it inherits the setting from the context that created it in the following ways:
-
When executing the set up a worker environment settings object algorithm, perform the following steps after the current step #4:
-
If inherited responsible browsing context’s insecure
requests policy is Upgrade, then:
- Set settings object’s insecure requests policy to Upgrade.
- For each value in inherited responsible browsing context’s upgrade insecure navigations set, add value to settings object’s upgrade insecure navigations set.
-
If inherited responsible browsing context’s insecure
requests policy is Upgrade, then:
3.4. Reporting Upgrades
Upgrading insecure requests MUST not interfere with an authors' ability to track down requests that would be insecure in a user agent that does not support upgrades. To that end, upgrades MUST be performed after evaluating request against all monitored security policies, but before evaluating request against all enforced policies.
<img src="http://example.com/image.png">
,
and delivers the following HTTP headers:
Content-Security-Policy: upgrade-insecure-requests; default-src https: Content-Security-Policy-Report-Only: default-src https:; report-uri /endpoint
The user agent will fire off a request request that:
- Violates the policy being monitored, thereby delivering a violation report to
/endpoint
. - Is upgraded from
http://example.com/image.png
tohttps://example.com/image.png
. - Does not violate the policy being enforced.
Note: This will be significantly clarified once [CSP] is rewritten in terms of [FETCH].
4. Processing Algorithms
4.1. Upgrade request to a potentially secure URL, if appropriate
Given a request request, this algorithm will rewrite its url if the client from which the request originates
has opted-in to upgrades. It will also inject an Upgrade-Insecure-Requests
header field header for
insecure navigation requests in order to improve a server’s ability to
feature-detect a client’s upgrade capabilities.
We will not upgrade cross-origin navigation requests, with the exception of form submissions. Form submissions will be upgraded to mitigate the risk of data leakage via plaintext submissions.
Note: This algorithm is called as step #3 of the Main Fetch algorithm.
-
If request is a navigation request, append a
header named
Upgrade-Insecure-Requests
with a value of1
to request’s header-list if any of the following criteria are met:- request’s url is a priori insecure
- request’s url’s
host
is not a preloadable HSTS host
Note: User agents can choose to append the
Upgrade-Insecure-Requests
header field for other requests, as discussed in §3.2.1 The Upgrade-Insecure-Requests HTTP Request Header Field. -
If request is a navigation request, then:
- If request is a form submission, skip the remaining substeps, and continue upgrading request.
- Let tuple be a tuple of request’s url’s
host
andport
. -
If tuple is contained in client’s upgrade insecure navigations set, then skip the remaining
substeps, and continue upgrading request.
Note: We only upgrade top-level navigation requests for hosts that have explicitly opted-into the behavior for a particular protected resource, as described in §1.2 Examples. Performing upgrades for navigations to third-party resources brings a significantly higher potential for breakage, so we’re avoiding it for the moment.
- Return without further modifying request.
- Let upgrade state be the result of executing §4.2 Should insecure requests be upgraded for client? upon request’s client.
- If upgrade state is Do Not Upgrade, return without modifying request.
- If request’s url’s
scheme
ishttp
, set request’s url’sscheme
tohttps
, and return. -
If request’s urls
port
is80
, set request’s urlsport
to443
.Note: This will only change the URL’s port if the port is explicitly set to
80
. If the port is not set, or if it is set to some non-standard value, the user agent will not modify that value. This implementation makes the same tradeoffs as HSTS (see [RFC6797], and specifically step #5 of Section 8.3, and item #6 in Appendix A).
Note: Due to [FETCH]'s recursive nature, this algorithm will upgrade insecurely-redirected requests as well as insecure initial requests.
4.2. Should insecure requests be upgraded for client?
Given an request’s client client (an environment settings object), this algorithm
returns Enforced Upgrade
if a priori insecure requests associated with that client should be upgraded, or Do Not Upgrade otherwise. In short, this will check the client
and return the appropriate insecure requests policy set on it or its browsing context.
-
If client has a responsible document, return the value
of its insecure requests policy.
Note: This catches
Document
s orWorker
s whose policy is set directly by theupgrade-insecure-requests
directive, or which have inherited the policy from an embedding document. -
If client has a responsible browsing context, return the
value of its insecure requests policy.
Note: This catches requests triggered from detached clients. Not sure this is necessary, really, given the inheritance structure defined in §3.3 Policy Inheritance.
- Return Do Not Upgrade.
5. Modifications to WebSockets
WebSockets do not use the fetching algorithm, so we need to handle those requests separately.
The establish a WebSocket connection algorithm [RFC6455] is modified as follows:
-
After the current step 1 (and before the new step #2 introduced in [MIX]), perform the following step:
-
If secure is false:
- Let upgrade state be the result of executing §4.2 Should insecure requests be upgraded for client? upon the relevant settings object for client’s entry script.
- If upgrade state is Do Not Upgrade, skip the remaining substeps.
- Set secure to
true
. -
If port is
80
, set port to443
.Note: This will only change the URL’s port if the port is explicitly set to
80
. If the port is not set, or if it is set to some non-standard value, the user agent will not modify that value. This implementation makes the same tradeoffs as HSTS (see [RFC6797], and specifically step #5 of Section 8.3, and item #6 in Appendix A).
-
If secure is false:
6. Security Considerations
6.1. Interaction with HSTS
The upgrade-insecure-requests
directive does not replace
the Strict-Transport-Security
HTTP response header [RFC6797]. Authors who serve their site over secure transport SHOULD send
that header with an appropriate max-age
in order to ensure that
users are not subject to SSL stripping attacks by maliciously active network
attackers, or monitoring by maliciously passive network attackers.
6.2. CSP Violation Reports
When sending a violation report for an upgraded resource, user agents MUST
target the Document
or Worker
that triggered the request, rather
than the Document
or Worker
on which the upgrade-insecure-requests
directive was set. Due to §3.3 Policy Inheritance, the latter might be a cross-origin ancestor of the former, and
sending violation reports to that set of reporting endpoints could leak data
in unexpected ways.
Likewise, the SecurityPolicyViolationEvent
MUST NOT target any Document
other than the one which triggered the request, for the same
reasons.
7. Performance Considerations
The upgrade mechanism specified here adds Upgrade-Insecure-Requests:
1\r\n
to every outgoing navigation request to non-preloadable
HSTS hosts (as discussed at length on public-webappsec@, and w3c/webappsec#216).
The advantages and intent of the header are laid out in §3.2.1 The Upgrade-Insecure-Requests HTTP Request Header Field, and
though we’ve taken some steps to ensure that it won’t be a permanent fixture
of the platform (by carving out preloadable HSTS hosts), it’s going
to be a long, long time before the header vanishes.
User agents are encouraged to find additional carveouts, and implement them.
8. Authoring Considerations
8.1. Legacy Clients
Legacy clients which do support mixed content blocking [MIX], but do not
support the upgrade-insecure-requests
directive will
continue to have a suboptimal experience on pages containing a priori insecure URLs. Authors SHOULD ensure that
they collect violation reports in order
to determine which resources are most problematic for their users, and SHOULD
use that information to prioritize fixes for URLs in legacy content that
users will most likely request.
8.2. Relation to HSTS
The mechanism specified here deals only with the security policy for a
specific protected resource. It does not deprecate, replace, or in any
way reduce the value of the Strict-Transport-Security
HTTP
response header [RFC6797]. Authors can and should continue to use that
header to ensure that their users are not subject to SSL stripping downgrade
attacks, as the upgrade-insecure-requests
directive will
not ensure that users visiting your site via links on third-party sites will
be upgraded to HTTPS for the top-level navigation.
Likewise, the Strict-Transport-Security
header does not imply
the behavior that upgrade-insecure-requests
activates.
It only ensures that resources requested from an origin will never hit the
network insecurely.
We are intentionally keeping these concepts distinct, as authors may choose to activate one or the other behavior, but ought not be forced to bind them together.
9. IANA Considerations
The permanent message header field registry should be updated with the following registration: [RFC3864]
9.1. Upgrade-Insecure-Requests
- Header field name
- Upgrade-Insecure-Requests
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- This specification (See §3.2.1 The Upgrade-Insecure-Requests HTTP Request Header Field)
10. Acknowledgements
Anne van Kesteren helped ensure that the initial draft of this document was sane. Peter Eckersley and Daniel Kahn Gillmor clarified the problem space, and helped point out the impact.