Plaintext protocols such as HTTP can be vulnerable to eavesdropping attacks where an attacker is able to read the transmitted content. Luckily, Transport Layer Security (TLS) can encrypt the traffic and make it significantly harder for attackers to use this data if captured.
However, it is possible for attackers to circumvent TLS by forcing encrypted connections to use plaintext HTTP. To address this problem, the HTTP Strict Transport Security (HSTS) response header was introduced which forces the user's browser to visit a website only using TLS and not fall back to plaintext HTTP (for a set time).
How the Lighthouse audit fails
The audit will flag the following issues with the HSTS header:
- If there is no HSTS header found at all.
- If one of the recommended directives is missing (
max-age
,includedSubDomains
,preload
) - If the duration for the
max-age
directive is under one year (31536000 seconds). - If there a syntax error when parsing the header, such as an unknown directive.
Configure a strong HSTS policy
The optimal HSTS header configuration looks as follows:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
- The
max-age
directive specifies the amount of time the user's browser is forced to visit a website only using TLS (in seconds). After that time, it will be possible to reach the site using plain HTTP again if there is no HSTS header provided by the website (or temporary redirects from HTTP to HTTPS are in place). - Setting the
includeSubDomains
directive will enforce the header on any subdomains of the page URL sending the header initially. For example, having an HSTS header sent by google.com which includes theincludeSubDomains
directive would also enforce the HSTS header on mail.google.com. - Setting the
preload
directive and submitting the domain to the HSTS preload service will compile the domain into browser binaries that use the preloaded HSTS list (not just Google Chrome).
There are some risks when rolling out the HSTS header. Any features that require an unencrypted HTTP connection would effectively be broken for the time set in the max-age
directive. Potentially even longer if the preload
directive is applied.
To lower risks associated to the rollout, a staged approach is recommended:
Starting with a small
max-age
and only addincludeSubDomains
(nopreload
):max-age=3600; includeSubDomains
After some cooldown period (e.g., one week) with no reported issues, raise the
max-age
, for example:max-age=604800; includeSubDomains
If this initial phase is successful for an extended period of time (e.g., three months), the website and its subdomains should be added to the HSTS preload list and the
preload
directive should be added.max-age=63072000; includeSubDomains; preload