Skip to main content
Security
Published 8 min read

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

DirectiveMeaning
max-ageHow many seconds the browser should enforce HTTPS-only access after this response
includeSubDomainsExtends enforcement to every subdomain of the current host, not just the exact host
preloadA 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.

Strict-Transport-Security: max-age=31536000; includeSubDomains

This 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.

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.

Buy me a byte 💾