Website problems

Missing HSTS

`Strict-Transport-Security` tells a browser to use HTTPS for a domain without trying HTTP first, for a stated period. Without it, a visitor typing a bare domain name makes one plain HTTP request before being redirected — and that request can be intercepted and answered by anyone on the network path. HSTS closes that window for every visit after the first. It is also the security header hardest to reverse, because browsers honour it for its full stated duration.

What the header prevents

The first request. Typing `example.com` sends a plain HTTP request; a redirect answers it. The redirect is correct and it arrives after the request has already crossed the network.

An attacker on the path — a shared wireless network, a compromised router — can answer that request instead, serving a copy of the site over HTTP and relaying everything the visitor types.

HSTS means the browser upgrades the request internally on every subsequent visit: no plain request is ever sent, so there is nothing to intercept.

It also removes the click-through on certificate warnings, which is deliberate: a site that has committed to HTTPS should not offer visitors a way past a broken certificate.

What it does not do is protect the very first visit, before the header has ever been received. That is what preloading addresses.

The directives

`max-age=<seconds>` is how long the browser should remember. It is required, and it is the number that makes this hard to undo.

`includeSubDomains` extends the policy to every subdomain. Powerful and unforgiving: every subdomain, including ones created later, must then serve valid HTTPS or be unreachable.

`preload` signals intent to be included in the browser-maintained preload list, which ships inside browsers so even the first visit is protected.

A typical production value is `max-age=31536000; includeSubDomains` — one year, all subdomains — once HTTPS is verified everywhere.

`max-age=0` is how the policy is withdrawn, and it only reaches browsers that visit again while the previous policy is still live.

Why it is hard to undo

A browser that received `max-age=31536000` will use HTTPS for that domain for a year, regardless of what the site does afterwards.

If a subdomain covered by `includeSubDomains` cannot serve HTTPS, it is unreachable for those visitors — not degraded, unreachable — until the policy expires or they visit again and receive `max-age=0`.

Preloading is stronger again: the list is compiled into browsers, so removal requires a request to the list maintainers and then waiting for browser releases to propagate. That takes months.

This is why the deployment order matters more here than for any other header. Every other security header can be removed by deleting a line.

How to deploy it in stages

First, verify HTTPS works on every hostname you serve, including ones you had forgotten. A subdomain without a valid certificate is what turns this into an outage.

Start with a short lifetime: `max-age=300`. Five minutes limits the damage of any mistake to five minutes.

Raise it gradually — a day, a week, a month — checking each time that nothing broke.

Add `includeSubDomains` only after confirming every subdomain serves HTTPS, and only once the short `max-age` has proved the configuration.

Consider preloading last, and only if the domain will be HTTPS permanently. It is the least reversible step in a web configuration.

Throughout, keep the HTTP-to-HTTPS redirect in place. HSTS applies to browsers that have seen the header; the redirect serves everyone else.

How to check it yourself

`curl -I https://example.com | grep -i strict-transport-security` shows the header and its directives.

Read the value rather than its presence. `max-age=0` disables the policy while appearing configured, and a very short lifetime provides little protection.

Check subdomains individually if `includeSubDomains` is set, because that directive is a commitment on their behalf.

Note that the header is only honoured over HTTPS. Sending it on an HTTP response has no effect, which is occasionally how it appears configured and does nothing.

How VeriFixScan detects it

`transport.hsts` reports whether the header is sent on HTTPS responses, and `transport.hsts_directives` reports the parsed value — the lifetime, whether subdomains are included, whether preload is declared.

`transport.hsts_preload_list` reports whether the domain appears in the browser preload list, which is the difference between a policy that protects returning visitors and one that protects the first visit too.

`transport.http_redirect` covers the redirect that must remain in place regardless, and `transport.https` the underlying question of whether HTTPS works at all.

The report separates absent from present-and-weak, because a `max-age` of 300 and a `max-age` of 0 are different situations with the same header name.

Frequently asked questions

What max-age should I use?
Start at 300 seconds while validating, then raise it in stages to a year once HTTPS is confirmed everywhere. The value is a commitment browsers honour for its full duration.
Is includeSubDomains safe to add?
Only once every subdomain serves valid HTTPS, including ones created later. A subdomain that cannot becomes unreachable for anyone whose browser holds the policy.
Does HSTS replace the HTTP to HTTPS redirect?
No. HSTS only applies to browsers that have already received the header. The redirect serves first-time visitors and everything that is not a browser, and must stay.

Sources

Related

VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.

Scan a website