Strict-Transport-Security HTTP header
How to implement HSTS to enforce HTTPS connections and improve web application security across different platforms.
Abbreviated as HSTS, the Strict-Transport-Security HTTP header is used to improve the security of a browser connection to a website by enforcing the use of the encrypted HTTPS protocol.
The header tells browsers that a particular website should only be accessed via HTTPS and to redirect any HTTP requests to HTTPS.
It is another of the HTTP security headers, alongside X-Frame-Options, and part of a broader approach to securing web applications.
If you can ensure that your website will always present a valid TLS (SSL) certificate and be accessible over HTTPS, then it's advisable to make use of this header.
The use of the Strict-Transport-Security HTTP header is better than a 301 redirect from HTTP to HTTPS because the initial HTTP request is still vulnerable to a man-in-the-middle attack and a malicious actor intercepting the traffic could redirect the browser to an insecure or fake destination.
Directives
max-age=31536000
The max-age directive tells the browser how long to remember that a site must only be accessed via HTTPS. The duration is in seconds, and the recommended values are at least one year (31536000).
includeSubDomains
Optional. If the includeSubDomains directive is included, the HSTS rule applies to all subdomains of the domain.
preload
Optional and currently an unofficial directive. You can include this directive if you wish to include your website in Google's HSTS preload list, although you'll also need to use a max-age of 2 years (63072000) and use includeSubDomains
Strict-Transport-Security on localhost
When developing locally it's uncommon to use HTTPS, except in specific circumstances. In this case you won't have a TLS (SSL) certificate provisioned on your local server and you'll be making all network requests over HTTP.
So in this scenario it wouldn't be helpful for your browser to force the connection onto HTTPS - you'd just see a browser error.
Fortunately the HSTS header is ignored by browsers until a site is first accessed over HTTPS and with a valid certificate, so if you're working locally and you never access the site using HTTPS, you'll be ok.
You can also use conditional logic in your website or webserver code to remove the header in different environments.
How to set Strict-Transport-Security header in Apache
This example taken from the useful h5bp/server-configs-apache library (this version from v6.0.0, 5th December 2022):
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=16070400; includeSubDomains" "expr=%{HTTPS} == 'on'"
</IfModule>
How to set Strict-Transport-Security in PHP
The header can be set using the PHP header method:
<?php
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
?>
How to set Strict-Transport-Security in Yii 2
For Yii2, headers can be added site-wide by modifying the response object in the app config :
'components' => [
'response' => [
'on beforeSend' => function($event) {
$event->sender->headers->add('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
},
],
Note that Apache/.htaccess settings of a header will overwrite any value set in PHP.
How to set Strict-Transport-Security header in Node.js and Lambda@Edge / Cloudfront
For static websites or apps served via AWS CloudFront and/or with a Lambda@Edge function, the Strict-Transport-Security HTTP header can be set using the Node.js runtime, as follows:
Lambda@Edge (origin response event)
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
headers['strict-transport-security'] = [
{
key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubdomains'
}
];
callback(null, response);
};
CloudFront function
function handler(event) {
var response = event.response;
var headers = response.headers;
headers['strict-transport-security'] = { value: 'max-age=31536000; includeSubdomains'};
return response;
}