Bridge SSL

What is HSTS? HTTP Strict Transport Security explained

9 min readUpdated

HSTS (HTTP Strict Transport Security) is a response header that tells browsers to reach a site only over HTTPS and to remember that for a period the site sets. It is one of the terms in the SSL and TLS glossary, and its commitment outlasts the moment it is switched on: a browser keeps the policy for as long as the header told it to.

Defined in
RFC 6797, HTTP Strict Transport Security [1]
Sent as
the Strict-Transport-Security response header, honoured only over HTTPS [1]
Directives
max-age (required) and includeSubDomains (optional); preload belongs to the preload list, not the RFC [1][2]
Effect
http:// addresses become https:// inside the browser, and a TLS or certificate error ends the connection [1]
Leaves open
the first visit, unless the name is on a preload list [1]

What HSTS does

HSTS closes the gap that an HTTP-to-HTTPS redirect leaves open.

A site that redirects plain requests to HTTPS is doing the right thing, but the redirect itself travels unencrypted. An attacker on the network path can intercept that redirect and rewrite it to keep the browser on plain HTTP; hstspreload.org calls this a protocol downgrade [2].

Once a browser holds the policy from a Strict-Transport-Security header, it replaces http:// with https:// and an explicit port 80 with 443 before the request is sent [1]. Typing the address, following an old link or opening a bookmark all become HTTPS requests inside the browser. The server is not refusing anything; the client is declining to ask insecurely, and that is why the protection holds even when the network is hostile.

The policy also changes how certificate errors behave. For a host with HSTS, the browser must end the connection on any TLS or certificate error, and RFC 6797 asks for this with "no user recourse": no warning page with a button to continue [1]. hstspreload.org names two more attacks HSTS helps protect against: an observer reading the path of a clicked http:// link, and cookies seen, modified or injected on plain requests, the redirect included [2].

The header and its directives

The policy is one header in an HTTPS response. Its format is defined in RFC 6797 [1].

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • max-age Required. How long, in seconds from receipt, the browser treats the host as an HSTS host; RFC 6797 gives 31536000 seconds as approximately one year. max-age=0 tells the browser to delete the policy, includeSubDomains with it [1].

  • includeSubDomains Optional. Applies the policy to every subdomain of the host's name, and each of those names must then work over HTTPS [1].

  • preload Not defined in RFC 6797, which tells browsers to ignore directives they do not recognise [1]. The preload list reads it as the site's request to be included [2].

A browser stores the policy only from a response that arrived over HTTPS without certificate or TLS errors. It ignores the header on plain HTTP responses and never stores a policy for an address that is a bare IP [1].

The first-visit gap and the preload list

A browser learns the policy from a response, so the very first visit to a site, or the first after max-age has run out, can still go out in plain HTTP. RFC 6797 calls this the bootstrap MITM vulnerability and names a list preloaded into the browser as one remedy [1].

Chrome builds such a list into the browser: requests to a listed name are made only over HTTPS and fail if HTTPS is unavailable. hstspreload.org, which takes submissions for the list, says Firefox, Safari and Edge have preload lists based on Chrome's [2].

The same page recommends HSTS and does not recommend preloading. Chrome and Safari already upgrade HTTP navigations to HTTPS on their own, so the list adds protection only when that upgrade fails in the presence of an active attacker [2].

Preload requirements and removal

Submission goes through hstspreload.org, and a site must [2]:

  • serve a valid certificate;

  • redirect from HTTP to HTTPS on the same host, if it listens on port 80;

  • serve all subdomains over HTTPS, including www when a DNS record for it exists; preloading also covers internal subdomains that are not publicly accessible;

  • send the header on the base domain over HTTPS with a max-age of at least 31536000 seconds, includeSubDomains and preload. An extra redirect served over HTTPS must carry the header itself.

Removal is possible but slow. hstspreload.org states that it takes months for a removal to reach users with a Chrome update, and that it cannot make guarantees about other browsers [2]. Treat preloading as close to permanent.

How to roll out HSTS without locking yourself out

hstspreload.org gives a staged rollout for HSTS [2]:

  1. Check that all subdomains work over HTTPS, nested and internal ones included.

  2. Send the header on all HTTPS responses, raising max-age in stages: max-age=300; includeSubDomains (5 minutes), then max-age=604800; includeSubDomains (1 week), then max-age=2592000; includeSubDomains (1 month).

  3. At each stage, look for broken pages, fix them, and wait the full max-age before moving on: a month at the last stage.

The waiting is the point. max-age is a time to live counted from the moment the browser received the header [1], so a policy received with 300 seconds lapses five minutes later, and one received with a year stays for a year. Preloading is a separate decision that comes after all this, if at all: the preload list asks for a max-age of at least a year [2].

How to check whether a site sends it

Ask the site for its headers over HTTPS and look for the policy:

$ curl -sI https://example.com | grep -i strict-transport-security

No output means no policy on that response. In the browser, the network panel of the developer tools shows the same header on the response.

In Chrome, the internal page chrome://net-internals/#hsts queries what the browser has stored for a name and deletes a policy it learned from a header; preloaded entries cannot be deleted there [3]. hstspreload.org points to the same page for checking the current preload list [2].

A scanner finding titled "HSTS Missing From HTTPS Server", Nessus plugin 84502, means exactly that: the HTTPS responses carry no such header. Nessus rates it Info [4]. It is a hardening recommendation, not an error a visitor ever sees.

Common mistakes

  • A long max-age on the first try. The browser keeps the policy until it expires, and a shorter value reaches only visitors who come back and receive it [1]. If the certificate lapses in the meantime, those visitors get a certificate error they cannot click past [1].

  • includeSubDomains without an inventory. The policy then covers names run by other teams, other systems, or nothing at all, and each of them must work over HTTPS from that moment. The names you forgot are the ones that break.

  • Sending the HSTS header over HTTP. Browsers ignore it there, so a configuration that only adds it to plain responses protects nobody [1].

  • Putting it in a meta tag. Browsers do not act on <meta http-equiv="Strict-Transport-Security">; the policy has to be a response header [1].

  • Testing on a host the browser does not trust. A header that arrives over a connection with certificate errors is not stored [1], so a test host with an untrusted certificate never gets a policy, even after the warning is clicked through.

  • Preloading as a first step. The safe order is the reverse: ramp max-age up in stages, and submit to the preload list last.

What HSTS does not do

HSTS controls how the browser reaches a site, not whether the site is trustworthy. RFC 6797 lists phishing on a fake site under another domain, and malicious code on the user's own system, among the threats it does not address [1]. It does nothing on the first visit from a browser that has never received the policy, for a name that is not on a preload list. What it removes is one specific path: a plain request, or the redirect that answers it, intercepted by someone on the network.

Nor does it restrict which certificates a browser accepts for the name; that was the job of HPKP, the browser form of certificate pinning, which Chrome has removed and MDN lists as obsolete [5]. Which certificate authorities may issue for a domain is set by a CAA record in its DNS, not by an HTTP header.

FAQ

What is HSTS?

HSTS is a response header that tells browsers to use only HTTPS for a site and to remember that for the period set in max-age. Once a browser has it, plain requests to that name are upgraded inside the browser before anything is sent.

How do I turn HSTS off?

On the site, send the header with max-age=0; browsers that come back and receive it delete the policy. For testing, chrome://net-internals/#hsts in Chrome deletes a policy learned from a header, but not a preloaded entry: that one has to come off the preload list, which takes months to reach users.

What does "HSTS missing from HTTPS server" mean?

It means the site's HTTPS responses do not include a Strict-Transport-Security header. Scanners report it as a hardening finding; visitors see no error, but their first plain request can still be intercepted.

Should I submit my site to the HSTS preload list?

hstspreload.org does not recommend preloading. Submit only once every subdomain works over HTTPS for the long term: the list requires includeSubDomains and a max-age of at least one year, and removal takes months.

Does HSTS replace the redirect from HTTP to HTTPS?

No. The redirect is still needed for the first visit and for clients without the policy, and the preload list requires it on a site that listens on port 80. HSTS makes the redirect unnecessary only for browsers that already hold the policy and whose max-age has not run out.

The connection itself is covered under TLS, certificates under certificates, and the warnings a browser shows when something is wrong under errors. The rest of the vocabulary is in this glossary.

Sources

  1. IETF, RFC 6797, HTTP Strict Transport Security: §2.3.2 (threats not addressed), §6.1–6.2 (header, max-age, includeSubDomains), §8.1 (processing, IP addresses), §8.3 (URI loading and port mapping), §8.4 (errors in secure transport establishment), §8.5 (meta element), §12.1 (no user recourse), §12.3 and §14.6 (pre-loaded list, bootstrap MITM vulnerability).

  2. hstspreload.org, HSTS Preload List Submission: benefits of HSTS, deployment recommendations, preloading, submission requirements, removal.

  3. Chromium source, chrome/browser/resources/net_internals/index.html: Query HSTS domain; Delete domain security policies.

  4. Tenable, Nessus plugin 84502, HSTS Missing From HTTPS Server.

  5. Chrome Platform Status, Remove HTTP-Based Public Key Pinning; MDN Web Docs, Glossary: HPKP.