Add an HSTS header
headers-hsts
Without Strict-Transport-Security a browser still tries plain HTTP first, and one intercepted request is enough to steal a session cookie.
CDN and edge
Web servers
Frameworks
Cloudflare
- 1 Go to SSL/TLS > Edge Certificates
- 2 Scroll down to HTTP Strict Transport Security (HSTS)
- 3 Enable HSTS and set Max-Age to at least 12 months
- 4 Enable includeSubDomains if all subdomains use HTTPS
Header name: Strict-Transport-Security
Value: max-age=31536000; includeSubDomainsAWS CloudFront
- 1 Create a Response Headers Policy in CloudFront
- 2 Attach the policy to your distribution's behavior
Custom header:
Name: Strict-Transport-Security
Value: max-age=31536000; includeSubDomains
Override origin: YesVercel
- 1 Add a headers entry to your vercel.json
- 2 Redeploy
json
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" }
]
}
]
}Netlify
- 1 Add a headers section to your netlify.toml or _headers file
- 2 Redeploy
toml
[[headers]]
for = "/*"
[headers.values]
Strict-Transport-Security = "max-age=31536000; includeSubDomains"Nginx
- 1 Add the header directive to your server or location block
- 2 Test config with nginx -t, then reload
nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Apache
- 1 Make sure mod_headers is enabled
- 2 Add the Header directive to your .htaccess or VirtualHost
apacheconf
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"Caddy
- 1 Add a header directive to your Caddyfile
- 2 Reload Caddy
caddyfile
header Strict-Transport-Security "max-age=31536000; includeSubDomains"Next.js
- 1 Add a headers function to your next.config.js
- 2 Rebuild and redeploy
javascript
// next.config.js
module.exports = {
async headers() {
return [{
source: "/(.*)",
headers: [
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
],
}];
},
};Express
- 1 Use the helmet middleware (recommended) or set the header manually
- 2 Restart your server
javascript
// Using helmet (recommended)
const helmet = require("helmet");
app.use(helmet());
// Or manually
app.use((req, res, next) => {
res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
next();
});Django
- 1 Enable HSTS in your settings.py
- 2 Make sure SecurityMiddleware is in MIDDLEWARE
python
# settings.py
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = TrueLaravel
- 1 Add a middleware that sets the header
- 2 Register it in your HTTP kernel
php
// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
return $response;
}Rails
- 1 Enable force_ssl which includes HSTS
ruby
# config/environments/production.rb
config.force_ssl = true
config.ssl_options = {
hsts: { subdomains: true, preload: true, expires: 1.year }
}Spring Boot
- 1 Configure HSTS in your security filter chain
java
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.headers(h -> h
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31536000)
)
);
return http.build();
}WordPress
- 1 Add the header via your theme's functions.php or .htaccess
- 2 A security plugin like HTTP Headers can also help
php
# .htaccess (Apache)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Or in functions.php
add_action('send_headers', function() {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
});Nuxt
- 1 Add the header to your nuxt.config.ts routeRules
- 2 Rebuild and redeploy
typescript
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/**': {
headers: { 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains' },
},
},
});ASP.NET
- 1 Add middleware in your Program.cs or Startup.cs
csharp
app.Use(async (context, next) =>
{
context.Response.Headers.Append("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
await next();
});Does your app still have this?
Scan your domain