# Strict-Transport-Security (/en/docs/web-security/security-headers/strict-transport-security)



HTTP Strict Transport Security (HSTS) is a response header a site sends over
HTTPS that tells the browser to reach that host over HTTPS only, for a period
you choose. Once the browser has seen the header, it rewrites any plain
`http://` address for the host to `https://` before the request ever leaves
the machine, even if the user typed the insecure address or followed an old
link.

Without it, typing a bare domain into the address bar starts with a plain
HTTP request, and anyone on the network path (a public Wi-Fi hotspot, a
compromised router) can read or rewrite that unencrypted hop and keep the
victim on an attacker-controlled HTTP version of the site. HSTS removes that
opening by making the browser refuse to speak plain HTTP to your host at all.

This is the header as you would ship it after a full rollout (see
[how to set it up](#how-to-set-it-up) before copying it):

```http
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
```

## Values and what each does [#values-and-what-each-does]

| Directive           | Status  | Description                                                                                                                                                                                    |
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `max-age=<seconds>` | ✅ Good  | Required. How long the browser enforces HTTPS for the host. The timer refreshes on every response, so a fixed value effectively never expires for returning visitors.                          |
| `includeSubDomains` | ✅ Good  | Extends the policy from the host to all of its subdomains, downward only.                                                                                                                      |
| `preload`           | ✅ Good  | Opts in to the browser preload list at [hstspreload.org](https://hstspreload.org/). Non-standard (not in RFC 6797) and hard to undo; submit only when the whole domain is ready.               |
| `max-age=0`         | ❌ Risky | The off switch. Tells the browser to forget the policy, including `includeSubDomains`. Use it only to roll back, and note it takes effect only on the next response received over valid HTTPS. |

The policy attaches to the exact host that served the header. A header on
`www.example.com` never covers `example.com`, and it covers subdomains only
when `includeSubDomains` is present, and only downward: a policy on
`secure.example.com` covers `login.secure.example.com` but not `example.com`
or sibling hosts. HSTS identifies hosts by domain name only, so it never
applies to a host addressed by IP. Browsers ignore the header entirely when
it arrives over plain HTTP.

## What it protects against [#what-it-protects-against]

* **SSL stripping and downgrade attacks.** An active attacker on the network
  can intercept a plain HTTP request and serve an HTTP version of the site,
  silently keeping the victim off TLS. With HSTS the browser upgrades the URL
  before the request goes out, so there is no insecure request to intercept.
* **Cookie theft on the insecure first hop.** Without the header, the first
  request to a typed domain goes over plain HTTP, and any cookie without the
  `Secure` attribute (see [cookie security](/en/docs/web-security/security-headers/cookie-security))
  rides that hop in cleartext where a passive eavesdropper can copy it.
* **Same-host mixed-content mistakes.** URLs pointing at a known HSTS host
  are rewritten, so a stray `http://` image or script reference to your own
  host gets upgraded instead of loading insecurely.
* **Certificate spoofing via click-through.** For an HSTS host, the browser
  treats any certificate error as fatal. There is no "proceed anyway" button,
  so an attacker cannot rely on users clicking through a warning for a forged
  certificate.

## Risks without it [#risks-without-it]

Every fresh visit starts insecure. When a user types your domain or follows
an `http://` link, the browser sends the first request over plain HTTP and
waits for your redirect. That single unencrypted round trip is enough for an
attacker on the path to hijack the session: non-`Secure` cookies travel in
cleartext, and an active attacker can answer the request themselves and never
let the user reach HTTPS at all. A server-side redirect to HTTPS does not
close this gap, because the redirect only happens after the insecure request
has already been sent and possibly tampered with.

## Risks and gotchas when using it [#risks-and-gotchas-when-using-it]

* **The first visit is not protected.** HSTS only works after the browser has
  received the header once over valid HTTPS. The very first request from a
  new browser, and the first request after the policy expires, still goes out
  over plain HTTP unless the domain is on the preload list.
* **Preload is close to permanent.** OWASP warns of permanent consequences if
  a preloaded site ever needs to move back to HTTP. Removal from the list
  requires dropping the `preload` directive first, then takes 6 to 12 weeks
  to reach most Chrome users and longer for other browsers, and the
  submission requirements apply for as long as you are listed. With
  `includeSubDomains`, preloading also forces every subdomain onto HTTPS,
  including internal, HTTP-only hosts that browsers can no longer reach.
  Audit all nested subdomains before submitting.
* **Silent no-ops.** The most common misconfiguration is sending the header
  on plain HTTP responses, which browsers must ignore, so nothing happens and
  nothing warns you. The header is also ignored on responses with certificate
  errors. And because the policy binds to the exact host, serving it on
  `www.example.com` while the apex `example.com` sends nothing leaves the
  apex unprotected.

## How to set it up [#how-to-set-it-up]

Ramp `max-age` up in stages, as [hstspreload.org](https://hstspreload.org/)
recommends, so a mistake locks users out for minutes, not years:

1. Serve the whole site over HTTPS, including `www` and every subdomain you
   plan to cover.
2. Configure the HTTP listener to answer every request with a permanent (301)
   redirect to the HTTPS URL, without the HSTS header. RFC 6797 forbids
   sending it over insecure transport, and browsers ignore it there anyway.
3. Add the header to all HTTPS responses with a small value first:
   `max-age=300; includeSubDomains` (5 minutes).
4. Raise it to `max-age=604800` (1 week), then `max-age=2592000` (1 month),
   waiting out each stage's full `max-age` and watching for breakage before
   the next step.
5. Make sure the apex domain serves the header too, not just `www`; each host
   needs to receive it directly.
6. When nothing has broken, move to `max-age=63072000` (2 years) and, if you
   want first-visit protection, add `preload` and submit the domain at
   [hstspreload.org](https://hstspreload.org/).
7. Check the deployed header, and the rest of your response headers, with the
   [security headers scanner](/tools/security-headers).

## Recommendation [#recommendation]

Send `Strict-Transport-Security` on every HTTPS response, with a 2 year
`max-age`, `includeSubDomains`, and `preload` once the rollout is complete:

```http
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
```

This is the value the
[OWASP HTTP Strict Transport Security cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html)
recommends: a 2 year `max-age` with subdomain coverage and preload. Treat it
as the end state, not the starting point. Reach it through the staged ramp
above, and add `preload` only once every subdomain runs on HTTPS and you
accept that the decision is close to permanent.

## Browser support [#browser-support]

Baseline widely available: Chrome, Firefox, and Safari all enforce the
header, so support is effectively universal. The `preload` directive is not
part of RFC 6797, but the preload list it feeds is consumed by all major
browsers.

## FAQ [#faq]

### Does HSTS protect the first visit? [#does-hsts-protect-the-first-visit]

No. HSTS only takes effect after the browser has received the header once over
valid HTTPS, so the very first request from a new browser, and the first
request after the policy expires, still go out over plain HTTP. Preload closes
that gap by shipping the policy in the browser.

### What is a good max-age for HSTS? [#what-is-a-good-max-age-for-hsts]

Two years (`max-age=63072000`) with `includeSubDomains` and `preload`, the value
the OWASP cheat sheet recommends. Do not start there. Ramp up from a small value
like `max-age=300`, waiting out each stage and watching for breakage, then move
to the two-year end state once every subdomain runs on HTTPS.

### How do I turn off HSTS? [#how-do-i-turn-off-hsts]

Send `max-age=0` over HTTPS. The browser stops treating the host as a Known HSTS
Host on the next response it receives over valid HTTPS, and that clears
`includeSubDomains` too. If the domain is preloaded, drop the `preload`
directive first and use the removal form, which takes weeks to propagate.

### Does HSTS cover subdomains? [#does-hsts-cover-subdomains]

Only when `includeSubDomains` is present, and only downward. The policy attaches
to the exact host that served the header, so a header on `secure.example.com`
covers `login.secure.example.com` but not `example.com` or sibling hosts.
Without `includeSubDomains` it covers just the one host, so the apex must send
its own header.

## See also [#see-also]

* [Security headers overview](/en/docs/web-security/security-headers)
* [CSP upgrade-insecure-requests](/en/docs/web-security/policies/content-security-policy/directives/upgrade-insecure-requests),
  which upgrades insecure subresources inside your pages; it complements HSTS
  rather than replacing it
* [Cookie security](/en/docs/web-security/security-headers/cookie-security)
  for the `Secure` attribute HSTS does not replace
* [Deprecated headers](/en/docs/web-security/security-headers/deprecated-headers),
  the TLS-era headers (HPKP, Expect-CT) that did not survive
* [Security headers scanner](/tools/security-headers) to check your
  deployed headers

## Sources [#sources]

* [RFC 6797, HTTP Strict Transport Security](https://datatracker.ietf.org/doc/html/rfc6797)
* [MDN, Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security)
* [OWASP, HTTP Strict Transport Security cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html)
* [hstspreload.org, the HSTS preload list](https://hstspreload.org/)
