Strict Transport Security
A mechanism to instruct user-agents (e.g. browsers such as Chrome and Firefox) that they are to interact with a website only over a secure connection.
Strict-Transport-Security: max-age=<seconds>; [includeSubDomains]; [preload]
Strict Transport Security, also known as HSTS, provides a mechanism for sites to instruct user-agents (e.g. browsers such as Chrome and Firefox) to only interact with that site over a secure connection, i.e. over HTTPS. Delivered as an HTTP header its value, also known as the policy, includes one or more directives which specify the duration of the policy and whether or not to enforce it on sub-domains also.
Assuming the policy is valid and is securely delivered, a compliant user-agent will immediately begin to enforce two key behaviours.
The behaviour will also be applied to any future attempts by the user to type the insecure HTTP address of the site directly into the user-agent’s address bar.
In Google Chrome this behaviour can be observed in the “Network” tab of the developer tools as an insecure HTTP request receiving a 307 Internal Redirect status code and a secure request over HTTPS being issued instead.
The second behaviour the user-agent will enforce is to block, without giving the user any option to override, any requests to the domain which encounter a certificate or other security related error.
For example, the user-agent will automatically block requests where a host presents a self-signed certificate issued by an untrusted authority. In instances where a self-signed certificate is required, one potential solution is to configure the user-agent or its operating system to explicitly trust the certificate or its issuing authority (e.g. via Group Policy in a Windows domain environment).
Policies must be delivered as a header, no meta tag http-equiv exists.
Before a policy will be enforced by the user-agent, it must have been delivered over a secure connection. In practical terms that means delivered over HTTPS and that the certificate presented by the host was trusted. User-agents will ignore any policy delivered over an insecure connection.
The overwhelming majority of user-agents will initially attempt to connect to a host via insecure HTTP whenever a URL is typed directly into their address bar or when a link is followed which doesn’t explicitly specify the HTTPS scheme (e.g. simply typing in www.martellosecurity.com).
This presents a problem which many sites attempt to resolve by redirecting any inbound HTTP requests to HTTPS automatically (e.g. via a 301 Redirect). This is effective for the most part but it does introduce a problem.
First Request Problem
The initial request over HTTP is by definition insecure and therefore, could be intercepted by a Man in the Middle attack and the response tampered with. For example, a bad actor could prevent the redirection to HTTPS or redirect an unsuspecting user to an entirely different and ultimately nefarious location.
As can be seen below, a solution to this problem exists whereby user-agents preload a list of sites which support HTTPS only. Doing so has the same effect as if the sites policy had been delivered with the user-agent pre-installed. This is an opt-in solution and site administrators can manually submit their domains to the canonical preload list³ used by most user-agent vendors.
We recommend delivering the policy from all hosts on your domain so that regardless of user entry-point, your policy gets delivered.
Whilst there are three potential directives which can be included with the header, the RFC¹ only defines two and actually requires only one.
The max-age directive is required and specifies the number of seconds after receipt of the header during which the user-agent should enforce the policy for this domain and potentially, subdomains also.
Common values for the directive range from as little as
max-age=3600 (one hour) to
max-age=31536000 (one year) or more. Which value is appropriate for your domain depends on a number of factors. However, there is little benefit to shorter timeframes and little drawback to longer ones.
We recommend setting your max-age to one year unless you have specific reasons to use a different period. Note that if you want to take advantage of the preloading mechanism discussed previously, your max-age directive must be at least one year.
The enforcement period can always be overidden by securely delivering a policy with a different max-age. A special case is
max-age=0 which instructs the user-agent to disregard any existing policy it holds for the domain.
The includeSubDomains directive is optional but when present it instructs the user-agent that the policy applies to this domain and its subdomains. For example, delivering a policy from www.martellosecurity.com with the
includeSubDomains directive would instruct the user-agent to enforce the policy not just for hosts on the martellosecurity.com domain, but hosts such as eu.cdn.martellosecurity.com also.
While we recommend inclusion of sub-domains on your policy there are a number of valid reasons to exclude it. For example, you may have legacy applications or clients using a sub-domain which have not yet been upgraded to support HTTPS only operation. Adding
includeSubDomains to your policy in these circumstances may break those applications.
Note that if you want to take advantage of the preloading mechanism discussed previously, your policy must contain the
The preload directive is also optional. Whilst the directive itself does not appear in the RFC¹, it does include the topic of preload lists. As discussed above, preloading is essentially the same as having your policy pre-installed by a user-agent and mitigating against the insecure first request problem.
In order for your policy to be eligible for inclusion on the preload list³ it must specificy a max-age of at least one year and must contain both the includeSubDomains and preload directives. Failure to comply with any of these three requirements will prevent your policy from being included on the list or make it eligible for deletion at a later date if it has changed.
A minimum eligible policy would therefore look as follows:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
We recommend not including the preload directive initially however as removal from the list could take a considerable amount of time. Give yourself a chance to discover and resolve any issues created by the policy before fully committing to HTTPS only as a user-agent pre-install.