search by tags

for the user

adventures into the land of the command line

implementing the hsts header with an nginx reverse proxy

the HTTP Strict Transport Security (HSTS) header allows a host to enforce the use of HTTPS on the client side by informing the browser to only use HTTPS, even if the user specifies HTTP as the protocol. The browser will then enforce the use of HTTPS. this protects the user from various forms of SSL stripping attacks.

in practice, the host server returns the HSTS header with responses sent over HTTPS. once the browser picks up on the header, it will from then on, only communicate with the host using a secure transport layer for the duration of ‘max-age’ set in the header.

the 'includeSubDomains’ directive is fairly self explanatory, but the 'max-age’ values specifies how long, in seconds, you want the client to treat you as an HSTS host. that is, how long you want them to contact you using HTTPS exclusively. The value used here is 1 year and each time the client visits the site and receives the header, the timer is reset back to a year.

to implement this in an nginx reverse proxy, simply add this line in your location part

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

just like this

server {
    listen                      443;
    server_name                 127.0.0.1;
    access_log                  /var/log/nginx/nginx_access.log;
    error_log                   /var/log/nginx/nginx_error.log;
    add_header                  Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    ssl                         on;
    ssl_certificate             /etc/ssl/ssl.crt;
    ssl_certificate_key         /etc/ssl/ssl.key;
    ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers   on;
    ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4 !MEDIUM";
    ssl_dhparam                 /etc/ssl/ssl.pem;
    keepalive_timeout           10;
    ssl_session_cache           shared:SSL:10m;
    ssl_session_timeout         10m;

    location / {
        proxy_pass http://0.0.0.0:5002;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header Front-End-Https on;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    }

    location /static {
        root /var/www/myapp;
    }
}

From the nginx docs, “NGINX configuration blocks inherit add_header directives from their enclosing blocks, so you just need to place the add_header directive in the top-level server block. There’s one important exception: if a block includes an add_header directive itself, it does not inherit headers from enclosing blocks, and you need to redeclare all add_header directives”.