How to hide Nginx web server version in responses

Asking for a web server’s version

There are many ways in which an attacker can find a vulnerability in a website. One of them is by knowing the version of the web server that the site uses and then looking up known vulnerabilities for that version. How can they find out the version? It’s surprisingly easy, actually. They just need to ask.

Most web servers are glad to tell you who they are and what version they are in each response. Below is a response header from an Nginx web server running locally in a container. It is using all of the default Nginx configurations.

If you want to follow along, you can run a container as shown below. This will use the nginx.conf file that is packaged with Nginx.

$ docker run --rm -d -p 8080:80 nginx
$ curl -v localhost:8080
...
< HTTP/1.1 200 OK
< Server: nginx/1.15.3
< Date: Fri, 14 Sep 2018 19:33:26 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 28 Aug 2018 13:32:13 GMT
< Connection: keep-alive
< ETag: "5b854edd-264"
< Accept-Ranges: bytes
...

In the response above, the Server header contains the type of server (nginx) as well as the version (1.15.3).

Removing the version from Nginx responses

Luckily, Nginx provides a directive to remove the version: server_tokens. By default, the version appears in a response, as demonstrated above. To remove it, add server_tokens off; to the http, server, or location context.

If you aren’t familiar with the terminology, directives are how you control behavior (server_tokens in this case) and contexts define the scope in which a directive is used; an area within { } is a context. Contexts are hierarchical so location is a child of server, which is a child of http. If you’re still confused, and it’s ok if you are, you can find a great tutorial on DigitalOcean on Nginx configuration. You won’t need it for the rest of this post but I recommend reading it later.

Below is an example configuration file (nginx.conf) that contains the server_tokens off directive in the http context. By applying it to the http context, any server, and consequently any location, will also inherit it. If for some reason you wish to change the behavior in a server or location context, you can override the directive by adding server_tokens on.

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    server_tokens off;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

If you’re still following along, stop the first container and start a new one that volume mounts the new configuration file and replaces the existing one.

$ docker run --rm -d -p 8080:80 --name=ngnix -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf nginx

Verify version is absent

With the new configuration in place, and Nginx restarted, make another request to the same endpoint.

$ curl -v localhost:8080
...
< HTTP/1.1 200 OK
< Server: nginx
< Date: Fri, 14 Sep 2018 19:52:51 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 28 Aug 2018 13:32:13 GMT
< Connection: keep-alive
< ETag: "5b854edd-264"
< Accept-Ranges: bytes

Now, the Server header contains nginx but the version has been removed. And that’s it. This is something you can do today to help improve the security of your web server. Be sure to reload Nginx in order for the directive to be applied.

Conclusions

Removing the version of the web server in responses is one way to help decrease the likelihood of an attacker discovering a vulnerability in the web server. It is not a panacea but should be part of a defense-in-depth strategy. Nginx makes it easy to remove the version by setting server_tokens off in the http, server, or location context.

If you have questions or comments about this post, please leave them below. Thank you for taking time to learn more with Influential Code LLC.