Glossary
HSTS
HTTP Strict Transport Security is a response header that tells a browser to use HTTPS for a domain for a stated period, converting any plain-HTTP request internally before it is sent. It closes the gap a redirect cannot: with a redirect, the first plain request is still transmitted and can be intercepted; with HSTS, the browser never sends it. The commitment is real — for as long as `max-age` states, that browser will refuse to reach the site over HTTP at all.
The directives
`max-age` is the number of seconds the browser should remember the policy. Every visit refreshes it, so an active site keeps extending the window.
`includeSubDomains` applies the policy to every subdomain. It is required for preload and is the directive that causes accidents, because it covers subdomains you may have forgotten are served over plain HTTP.
`preload` signals consent to inclusion in the browser preload list. The directive by itself does nothing; submission to the list is a separate step.
A short `max-age` — hours rather than months — is the sensible way to start, precisely because the policy cannot be recalled from browsers that already have it.
Why the first request is the gap it closes
A visitor typing a bare domain sends plain HTTP. The redirect to HTTPS arrives in the response, which means the request already travelled unprotected.
Anything on the network path saw it, and could have answered instead of the real server.
With an HSTS policy already stored, the browser rewrites the request to HTTPS before sending anything. There is no plain request to intercept.
The remaining gap is the very first visit ever, before any policy has been received — which is what the preload list exists to close.
Why it is hard to undo
The policy lives in the browser, not on the server. Removing the header does not remove the stored policy; it only stops refreshing it.
A browser holding a policy with a one-year `max-age` will refuse plain HTTP for that domain for up to a year, whatever the server now says.
The documented way to retract is to serve `max-age=0` over HTTPS and wait for visitors to receive it, which requires HTTPS to still be working.
So a site that enables HSTS with a long `max-age` and `includeSubDomains`, and then finds a subdomain that cannot do HTTPS, has a real problem and no quick fix.
How to deploy it safely
Confirm every hostname under the domain serves HTTPS correctly with a valid certificate first, including ones you do not think of as websites.
Start with a short `max-age`, without `includeSubDomains`, and verify nothing breaks.
Raise the duration gradually, then add `includeSubDomains` once the subdomains are confirmed.
Check the header with `curl -I https://example.com | grep -i strict`. Note that browsers ignore the header when it arrives over plain HTTP, so it must be set on the HTTPS response.
Frequently asked questions
- Does HSTS replace the HTTP to HTTPS redirect?
- No. The redirect is still needed for the first visit and for clients that ignore the header. HSTS removes the plain request on subsequent visits.
- How do I turn HSTS off?
- Serve max-age=0 over HTTPS and wait for visitors to receive it. Removing the header alone leaves existing policies in place until they expire.
- What max-age should I use?
- Start with hours, verify nothing breaks, then increase. A long duration is a commitment you cannot recall from browsers that already stored it.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website