In short
HSTS stands for HTTP Strict Transport Security and is a response
header that your web server sends to the browser. With it you tell the browser:
"From now on and for the next X seconds, load this domain exclusively over HTTPS —
no matter whether the user clicks an
http:// link or types the
address without a protocol." The browser remembers this instruction and connects
directly via HTTPS on the next visit.
What problem does HSTS solve?
Without HSTS, the typical first visit looks like this: the user types
example.com into the browser,
the browser sends an HTTP request, and the server replies with an HTTPS redirect.
That very first unencrypted request is the weak spot: an attacker on the same Wi-Fi
can intercept the redirect, impersonate your site, and only establish the HTTPS
connection between themselves and your server — meanwhile the user keeps talking
unencrypted to the attacker (SSL stripping). With HSTS, the browser ignores the
HTTP attempt and goes straight to HTTPS.
Header structure
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age=31536000— how long (in seconds) the browser remembers the HSTS instruction. 31536000 = 1 year, which is the common value. Anything below 6 months is considered too short.includeSubDomains— the instruction also applies to all subdomains (e.g.api.example.com,blog.example.com). Important: every subdomain must then actually speak HTTPS.preload— you request inclusion in the browsers' HSTS preload list. This forces HTTPS on the very first visit, before the browser has ever seen the header.
HSTS Preload
The preload list
is hard-coded into Chrome, Firefox, Safari, and Edge. Anyone listed there will
never be requested via HTTP again — not even on the very first visit.
Requirements: a valid certificate, all subdomains on HTTPS, a
max-age of at least 31536000
(1 year), and both includeSubDomains
and preload set.
Risks
HSTS is almost impossible to roll back. If you deploy
max-age=31536000; includeSubDomains
and then notice that one subdomain doesn't have HTTPS at all — that subdomain
will be unreachable for a year, until each individual visitor's cache expires.
Recommendation: roll out in stages.
- Start with
max-age=300(5 minutes) withoutincludeSubDomains. - After a week, raise it to
max-age=86400(1 day). - Move all subdomains to HTTPS, then add
includeSubDomains. - Finally, set
max-age=31536000and optionallypreload.
Configuration examples
nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Cloudflare: in the dashboard under SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS).