HTTP Strict Transport Security (HSTS) not set

ID

javascript.http_strict_transport_security

Severity

high

Resource

Misconfiguration

Language

JavaScript

Tags

CWE:319, OWASP:2021:A2, PCI-DSS:6.5.1

Description

The HTTP Strict-Transport-Security response header (often abbreviated as HSTS) informs browsers that the site should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be upgraded to HTTPS.

This is more secure than configuring a HTTP to HTTPS (301) redirect on your server, as the initial HTTP connection is still vulnerable to a man-in-the-middle attack.

Rationale

The absence of HSTS allows for the transmission of sensitive information over insecure connections, making it vulnerable to man-in-the-middle attacks (where adversaries can intercept the initial HTTP connection before the redirect to HTTPS, potentially capturing sensitive data or hijacking the session) and protocol downgrade attacks (where adversaries can downgrade the connection from HTTPS to HTTP).

The primary purpose of HSTS is to enforce HTTPS connections and prevent these types of attacks by telling browsers to only connect to the website over HTTPS, even if a user tries to use HTTP. It is considered a crucial security header in modern web applications.

This detector checks if the response header Strict-Transport-Security is set.

The following is an example of an Express web application not using HSTS:

var express = require('express');
var https = require('https');

var app = express()
/* ... no configuration for HSTS ... */

var httpsConfig = {/* ... */}
// FLAW - no HSTS is reported here
var httpsServer = https.createServer(httpsConfig, app);
httpsServer.listen(8443);

Remediation

The recommended way to implement HSTS is with a header like: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload.

Read HTTP Strict Transport Security for full details of the header.

In particular, read the Deployment Recommendations if you want to enable HSTS to avoid broken pages with HTTP.

var express = require('express');
var https = require('https');
var helmet = require('helmet');

var app = express()

// FIXED - Sets HSTS for 60 days
// Strict-Transport-Security: max-age=5184000; includeSubDomains
app.use(helmet.hsts({ maxAge: 5184000 }))

// Or use the default for helmet(), which is equivalent to
// Strict-Transport-Security: max-age=15552000; includeSubDomains (180 days)
app.use(helmet());

var httpsConfig = {/* ... */}
var httpsServer = https.createServer(httpsConfig, app);
httpsServer.listen(8443);

Configuration

The rule does not have any configuration options.

References