Strict-Transport-Security security response
Tells browsers to only ever connect to this site over HTTPS — and to remember that for a specified duration.
What it does
Strict-Transport-Security (HSTS) tells browsers: "This site is HTTPS-only. Don't ever connect over HTTP — not now, not in the future, not for any reason." Once a browser receives this header, it automatically upgrades any HTTP requests to HTTPS for the declared duration, without making a network request first.
It closes a specific attack window: the first HTTP request a browser makes before being redirected to HTTPS. Without HSTS, an attacker doing a man-in-the-middle attack can intercept that first HTTP request (an SSL stripping attack) before the server has a chance to redirect. With HSTS, the browser never sends the HTTP request at all.
Syntax
Strict-Transport-Security: max-age=<seconds>[; includeSubDomains][; preload]
Examples:
Strict-Transport-Security: max-age=31536000
Strict-Transport-Security: max-age=31536000; includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Directives
max-age=<seconds>
How long (in seconds) the browser should remember and enforce HTTPS-only. The browser caches this value and refreshes it each time it receives the header.
| Duration | Seconds |
|---|---|
| 1 hour | 3600 |
| 1 day | 86400 |
| 1 month | 2592000 |
| 6 months | 15768000 |
| 1 year | 31536000 |
| 2 years | 63072000 |
A max-age of 0 clears the HSTS policy — the browser reverts to normal behaviour.
includeSubDomains
Extends the policy to all subdomains of the current domain. Strict-Transport-Security: max-age=31536000; includeSubDomains means every subdomain — app.example.com, api.example.com, mail.example.com — must be HTTPS.
Use with caution. If any subdomain doesn't support HTTPS, adding includeSubDomains will break it. Audit all subdomains before enabling this.
preload
Signals that you want your domain added to browsers' built-in HSTS preload lists. Browsers ship with a hardcoded list of HSTS domains — these sites are HTTPS-only from day one, before the browser has ever connected to them.
Requirements for preload submission:
max-ageof at least 31536000 (1 year)includeSubDomainsmust be presentpreloadmust be present- The entire domain and all subdomains must support HTTPS
Submit at hstspreload.org. This is difficult to reverse — once you're on the preload list, removal takes months and ships with a browser release. Don't add preload until you're 100% committed to HTTPS across your entire domain.
How HSTS actually works
Without HSTS:
User types "example.com" → Browser requests http://example.com → Server redirects to https://example.com → HTTPS connection
That first HTTP request is the vulnerability window.
With HSTS (after first visit):
User types "example.com" → Browser knows HSTS is active → Internally upgrades to https://example.com → HTTPS connection
The HTTP request never leaves the browser.
With preload:
First ever visit → Browser already knows HSTS from preload list → https:// from day one
No initial HTTP request even on the first visit.
Deployment strategy
Step 1 — Start with a short max-age:
Strict-Transport-Security: max-age=300
5 minutes. Test everything works. Check all subdomains. Verify no HTTP-only assets.
Step 2 — Increase to a month:
Strict-Transport-Security: max-age=2592000
Monitor for any HTTPS issues. Watch error logs.
Step 3 — Set to 1 year:
Strict-Transport-Security: max-age=31536000
Step 4 — Add includeSubDomains (after auditing subdomains):
Strict-Transport-Security: max-age=31536000; includeSubDomains
Step 5 — Add preload (only when fully committed):
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Common mistakes and gotchas
Setting HSTS before your HTTPS is solid. If your certificate expires, has an error, or you need to revert to HTTP for any reason, HSTS users will be locked out and see certificate errors with no bypass option. Only set HSTS after HTTPS is stable and permanent.
Setting HSTS over HTTP. Browsers ignore Strict-Transport-Security headers received over HTTP (an attacker could inject it). HSTS only takes effect when received over HTTPS.
Using includeSubDomains with unready subdomains. Any subdomain you've forgotten — an old staging environment, a legacy service, a third-party tool on a subdomain — will break for HSTS users. Audit everything.
Forgetting that max-age=0 is an emergency escape. If you need to revert HSTS, deploy Strict-Transport-Security: max-age=0 over HTTPS. This clears the cached HSTS policy. But it only helps users who visit after you deploy the fix — users who haven't visited recently still have the old policy cached.
Real-world examples
Minimal HSTS:
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=31536000
Full HSTS with subdomains:
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=31536000; includeSubDomains
Preload-ready:
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Clearing HSTS (emergency rollback):
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=0
FAQ
Does HSTS replace the HTTP→HTTPS redirect?
No — keep the redirect. HSTS only protects users who have already visited your site. New visitors, users in private browsing mode, and users whose HSTS cache has expired still need the redirect. HSTS and the redirect are complementary: the redirect handles first visits; HSTS handles subsequent ones.
What happens if my SSL certificate expires with HSTS active?
Users see a certificate error with no option to bypass it ("click through"). This is intentional — HSTS removes the bypass option. This is why you should start with a short max-age and always have certificate renewal automated.
Does HSTS protect against all MITM attacks?
It protects against SSL stripping attacks on HTTP connections. It doesn't protect against attacks where the attacker has a valid certificate for your domain (CA compromise, internal CA in corporate environments) or attacks at the DNS level. HSTS is one layer of a defence-in-depth approach.
Can I set HSTS on a development environment?
Don't. If you set HSTS on localhost or a dev domain and then later need HTTP for that domain, you'll have to manually clear the HSTS cache in your browser (or wait for max-age to expire). Development environments should use HTTP or self-signed HTTPS without HSTS.
Fun fact
HSTS was invented by Jeff Hodges, Collin Jackson, and Adam Barth in 2009, directly inspired by Moxie Marlinspike's presentation at Black Hat 2009 where he demonstrated SSL stripping attacks in practice. The attack was elegant and devastating — a MITM attacker intercepts the first HTTP request and never lets the browser upgrade to HTTPS, silently proxying a downgraded connection. HSTS was the spec response: remove the HTTP entry point entirely. RFC 6797 was published in 2012. Today it's supported by every major browser and is considered a baseline requirement for any production HTTPS site.