How to Properly Implement HSTS in Nginx Configuration for Enhanced Security


1 views

HTTP Strict Transport Security (HSTS) is a crucial web security policy mechanism that helps protect websites against protocol downgrade attacks and cookie hijacking. Even with proper HTTP-to-HTTPS redirects in place, adding HSTS provides an additional layer of security by instructing browsers to always use HTTPS for future requests.

While your current nginx configuration correctly handles HTTP-to-HTTPS redirects, there are several benefits to implementing HSTS:

  • Eliminates the initial insecure HTTP request entirely after the first secure visit
  • Protects against SSL-stripping man-in-the-middle attacks
  • Prevents users from accessing your site with invalid certificates
  • Improves page load performance by skipping the redirect step

For optimal security, add the HSTS header to your HTTPS server block:

server {
    server_name example.com;
    listen 443 ssl;
    
    ssl_certificate /etc/nginx/ssl/cert_chain.crt;
    # other SSL configuration...
    
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # rest of your configuration...
}

When implementing HSTS, keep these factors in mind:

  • Testing Phase: Start with a smaller max-age (e.g., 300 seconds) before committing to 31536000 (1 year)
  • Subdomains: The includeSubDomains directive affects ALL subdomains
  • Preload: Consider submitting to HSTS preload lists after thorough testing
  • Rollback: Once set with a long max-age, it's difficult to remove HSTS from clients

Here's a comprehensive example incorporating all security best practices:

# HTTP to HTTPS redirect
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

# HTTPS with HSTS
server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
    # Your application configuration...
}

While redirecting HTTP to HTTPS (and www to non-www) is a great first step for security, adding HSTS (HTTP Strict Transport Security) provides crucial additional protection. The redirect approach still leaves a vulnerability window during the initial HTTP request where attackers could potentially intercept or manipulate traffic.

By adding the HSTS header, you instruct browsers to:

  • Automatically convert all HTTP links to HTTPS for your domain
  • Enforce HTTPS for all subsequent visits (for the specified max-age period)
  • Apply the policy to all subdomains (when includeSubDomains is set)
  • Prevent users from bypassing certificate warnings

Here's how to modify your existing configuration to include HSTS:

server {
    server_name example.com www.example.com;
    listen 80;
    return 301 https://example.com$request_uri;
}

server {
    server_name www.example.com;
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/cert_chain.crt;
    # ... other SSL related config ...
    return 301 https://example.com$request_uri;
}

server {
    server_name example.com;
    listen 443 ssl;
    # ... other SSL related config ...
    
    # Add HSTS header (31536000 seconds = 1 year)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # ... remaining server configuration ...
}

Before implementing HSTS:

  • Ensure your HTTPS implementation is stable and properly configured
  • Start with a shorter max-age (like 300 seconds) for testing
  • Consider preloading your domain in browser HSTS lists for maximum protection
  • Be aware that includeSubDomains will enforce HTTPS on all subdomains

After applying the changes, verify the header is present:

curl -I https://example.com

You should see the Strict-Transport-Security header in the response.

The main considerations are:

  • If you need to temporarily disable HTTPS, users with cached HSTS policies won't be able to access your site
  • Incorrect implementation can lock users out of your site
  • Changes to your SSL configuration become more critical