Prevent Arbitary HTTP Host header in nginx

Reinis Rozitis r at roze.lv
Fri Feb 28 15:38:24 UTC 2020


> I did follow your steps. My nginx.conf file is https://paste.centos.org/view/ae22889e when I run the curl call, I am still receiving HTTP 200 OK response instead of HTTP 444 (No Response) as per the below output

If you've just called config reload then most likely your nginx is still using an old configuration (you should always check with: nginx -t).


I tried to make a simple test case and turns out you can't have just 'listen 443;' directive (even there is no 'ssl' option) in one server block if another has ' listen 443 ssl;' nginx requires to specify a "ssl_certificate" (which is kind of understandable if you know that nginx has several caveats regarding listen ip:port pairs).

The error looks like:

nginx  -t
nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive in nginx.conf:39
nginx: configuration file nginx.conf test failed

So before writing solutions out of head one should always note that and/or test your own suggestions :)



The correct configuration example should look like this (for somedummy.crt/key certificate you can either use some self signed or just any other valid certificate (since nginx checks the validity of ssl certificates at startup/config reload you can't place nonexisting/nonvalid certs here)):



    server {
        listen 443;
        ssl_certificate      somedummy.crt;
        ssl_certificate_key  somedummy.key;
        server_name _;
        return       444;
    }

    server {
        listen 443 ssl;
        ssl_certificate      validdomain.crt;
        ssl_certificate_key  validdomain.key;
        server_name validdomain;
        return 200 'Works';
    }


Then the curl requests with Host injects should work as expected:

curl --verbose https://validdomain

> GET / HTTP/1.1
> Host: validdomain
>
< HTTP/1.1 200 OK
* Connection #0 to host validdomain left intact
Works


curl --verbose --header 'Host: invalidhost' https://validdomain

> GET / HTTP/1.1
> Host: invalidhost
>
* Empty reply from server
* Connection #0 to host validdomain left intact
curl: (52) Empty reply from server




p.s. for further testing you should note also that curl doesn't use the Host header for SNI (https://github.com/curl/curl/issues/607 ) rather than the one in the url

So something like:

curl --verbose --header 'Host: validhostname' https://127.0.0.1
will fail with:
curl: (51) SSL: no alternative certificate subject name matches target host name '127.0.0.1'


will fail but on the other hand (if your somedummy.crt has an actual domain):

curl --verbose --header 'Host: validdomain' https://somedummy

* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
> GET / HTTP/1.1
> Host: validdomain

< HTTP/1.1 200 OK
< Server: nginx/1.17.8
* Connection #0 to host somedummy left intact
Works

the dummy ssl certificate will be used but nginx will serve the validdoman virtualhost .

rr




More information about the nginx mailing list