5

Let's take the following nginx.conf configuration file with server blocks for example.com and subdomain.example.com:

http {
    ...

    server {
        listen [::]:80 ipv6only=off default_server;
        server_name example.com;
        return 301 https://example.com$request_uri;
    }
    server {
        listen [::]:443 ipv6only=off ssl default_server;
        server_name example.com;
        add_header Strict-Transport-Security
            "max-age=63072000; includeSubDomains; preload" always;
        ...
    }

    server {
        listen [::]:80 ipv6only=off;
        server_name subdomain.example.com;
        return 301 https://subdomain.example.com$request_uri;
    }
    server {
        listen [::]:443 ipv6only=off ssl;
        server_name subdomain.example.com;
        add_header Strict-Transport-Security
            "max-age=63072000; includeSubDomains; preload" always; # <-- again ???
        ...
    }
}

The includeSubDomains part of the header apparently tells the browser that the header applies to all subdomains as well.

However, if that browser were to visit subdomain.example.com before ever seeing example.com, that wouldn't be of any help, would it? So to cover for this scenario, I need to add the same add_header in all subdomain server blocks too ...right?

Will
  • 229
  • 3
  • 7

2 Answers2

7

You are correct that it's better to have the HSTS Strict-Transport-Security header everywhere you need it to make sure a client gets it even if sub.example.com is accessed before example.com or if the cached HSTS information has expired.

The includeSubDomains flag affects all subdomains of where it's present. This means that includeSubDomains on sub.example.com takes effect on *.sub.example.com instead of *.example.com. (This is only natural as it would be bad if e.g. example.co.uk could affect *.co.uk.)

  • If you don't use any sub.sub.example.com you could leave the Strict-Transport-Security header of your subdomains without this flag.

  • subA.example.com can't protect subB.example.com.

Esa Jokinen
  • 46,944
  • 3
  • 83
  • 129
5

Correct. The includeSubdomains option is used to enforce https on all resources linked inside an html page served by the current domain.

Quoting https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ :

For example, the HTML response for https://www.example.com can include a request to a resource from https://example.com, to make sure that HSTS is set for all subdomains of example.com.

Also beware that if you add an add_header directive inside a location { } block, you also need to redefine add_header Strict-Transport-Security ... inside that block. Quoting again:

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:

Luca Gibelli
  • 2,731
  • 1
  • 22
  • 30
  • I have a file with STS and other similar security headers that I include inside each server. – Tim May 27 '18 at 07:15
  • that's my point: it's not enough. This is a corner case, it might not apply to you, but for other readers it might be relevant: if you have e.g. ```add_header X-Proxy-Cache $upstream_cache_status``` inside a location {} block and you don't repeat ```add_header Strict-Transport-Security ...``` inside that location block, the ```add_header Strict-Transport-Security ...``` from the parent server {} block is *not inherited*!! – Luca Gibelli May 27 '18 at 08:24