What Is HSTS? Strict-Transport-Security Explained
HSTS closes a narrow but real window for downgrade attacks. Here's exactly what it enforces and how to configure it.
The first time a browser connects to a site, it doesn't yet know whether that site should always be reached over HTTPS - which leaves a narrow window where a request could be intercepted and downgraded to plain HTTP. HSTS is the header that closes that window for every subsequent visit.
The direct answer
Strict-Transport-Security: max-age=31536000 tells the browser: for the next year, never attempt a plain HTTP connection to this host - automatically upgrade any http:// request to https:// before it's sent, without a network round-trip.
The three directives
| Directive | Meaning |
|---|---|
| max-age | How many seconds the browser should enforce HTTPS-only access after this response |
| includeSubDomains | Extends enforcement to every subdomain of the current host, not just the exact host |
| preload | A signal of intent to be included in browser preload lists (see below) - doesn't do anything by itself |
Why the first connection is the risky one
HSTS only takes effect after the browser has seen the header at least once. That means the very first request to a site - before HSTS has been recorded - is not protected by it, and could theoretically still be intercepted on an insecure network and downgraded. This is exactly the gap the preload list exists to close.
The preload list
Browser vendors maintain a hardcoded list of domains that should always be accessed over HTTPS, even on the very first connection, before any HSTS header has ever been seen. Getting on this list requires meeting three header-level requirements (max-age of at least one year, includeSubDomains, and the preload directive) and then manually submitting the domain at hstspreload.org.
Preload is not easily reversible
Removing a domain from browser preload lists is slow and can take months to fully propagate across browser releases. Only add preload once you're confident every subdomain can support HTTPS indefinitely - it isn't something to enable as a default best practice without that certainty.
A recommended starting configuration
Strict-Transport-Security: max-age=31536000; includeSubDomainsThis gets the core protection (a full year of enforced HTTPS, extended to subdomains) without committing to the preload list until you're ready for that step.
Common mistakes
- Setting a very short max-age (like 60 seconds) and leaving it there - this narrows the protection window to almost nothing for anyone who hasn't visited recently.
- Adding includeSubDomains before confirming every subdomain actually supports HTTPS - this can break subdomains that don't yet have valid TLS configured.
- Enabling preload without understanding that removal is slow and difficult if you later need a subdomain to run over plain HTTP.
- Setting HSTS on a site that isn't yet reliably serving HTTPS everywhere, which can lock out users if HTTPS briefly becomes unavailable.
Checking your configuration
Paste your response headers into the HTTP Security Headers Analyzer to check your max-age, includeSubDomains, and preload configuration against these requirements, alongside the rest of your security headers.
Summary
HSTS removes the window for downgrade attacks by telling the browser to enforce HTTPS-only access for a set period. A one-year max-age with includeSubDomains is a solid baseline; preload is a separate, harder-to-reverse commitment worth making deliberately, not by default.
Frequently asked questions
- What does HSTS do?
- Strict-Transport-Security tells the browser to only ever connect to a site over HTTPS for a specified period, so even if a user types http:// or follows an old http:// link, the browser rewrites it to HTTPS before making the request.
- What max-age should I use for HSTS?
- 31536000 (one year) is the widely-recommended baseline and is required for preload list eligibility. Shorter values are reasonable while first rolling out HSTS, but the protection window shrinks with them.
- Should I enable HSTS preload?
- Only once you're confident every subdomain can support HTTPS indefinitely - preload list removal is slow and difficult, so it isn't something to enable by default without understanding that trade-off.
Try it yourself
The tool that pairs with this guide.
Did this help you tighten your security headers?
If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.
Related articles
HTTP Security Headers Explained: A Practical Developer Guide
A handful of response headers tell the browser how to defend the page they came with. Here's what each one actually does.
Published
Content-Security-Policy (CSP) Explained With Examples
CSP is an allow-list for where your page's resources can load from. Here's how the directives fit together.
Published
CORS Explained: Access-Control-Allow-Origin, Credentials and Common Mistakes
CORS is a browser-enforced exception to the same-origin policy. Here's how it works and the one combination that goes wrong constantly.
Published