Hide your Nginx Version

Abenezer Belachew

Abenezer Belachew · January 14, 2024

5 min read

  • Maybe this is just me being paranoid but hiding the Nginx version wouldn’t hurt. We all know that vulnerabilities are always there. People are sneaky and will eventually always find ways to break things, intentionally or not. I am personally aware of malicious bots that just crawl the web for vulnerabilities looking for their next victim. Often, their tactics are straightforward, such as locating admin pages and attempting brute-force attacks with common username and password combinations, or exploiting unpatched versions of tech stacks in applications.

  • Speaking of tech stakcs, Nginx is a widely used option used in a majority of web services for a variety of applications. Although I hold Nginx in high regard for its reliability, it, like many software platforms, has had to address a number of vulnerabilities over time. This awareness becomes particularly pertinent when considering the information exposed in server response headers. For instance, let’s say I use nginx/1.18.0. Making a request to a location served by an Nginx server yields the following response headers.

    first_response
    Head to the Network tab in DevTools and click on one of the requests served by Nginx.
  • Notice how the Server header has revealed the version of nginx I’m using and the OS it’s running on. It's generally fine, but hypothetically, if I were embarrassed about the Linux distro my site runs on (which I'm not), I wouldn't want Nginx revealing it to everyone in the response header.

  • Who knows? There might even be a distro-specific vulnerability. I don’t want it telling everyone (specially those crawlers) the OS my server is running on. In such a case, the transparency of Nginx in revealing system details in the response header could be a point of concern.

  • But it's not just the operating system that's of concern; the version of the software is equally troubling. Consider the possibility of a vulnerability existing in the current version of Nginx I'm using. Imagine if a critical bug were discovered in 1.18.0 at a time when I am unable to update to a newer version. This situation could be problematic. By displaying the Nginx version in the response header, I inadvertently increase the risk of becoming a target for malicious bots.

  • At this stage, by revealing the Nginx version in the response headers, I'm essentially broadcasting to all crawlers and potential attackers that my application might be vulnerable. It's like openly admitting a weakness without any attempt at concealment.

  • So, the pressing question arises: is it possible to avoid disclosing this information, to not let everyone know about potential vulnerabilities?

    • Fortunately, the answer is yes, and the solution is surprisingly trivial. 🦎

Let’s hide the version first

  • With a simple server_tokens off directive in your server block, you can hide the version.
server {
	...	
	# Dontshowtheversionofnginximscaredofgettinghacked
	server_tokens off;
	...
}

Test your config and reload it:

  • nginx -t
  • systemctl reload nginx

And now you’ll see this:

second_response
Much better. The server header is no longer showing the version
  • But can we do better? Can we not have nginx show up under Server header? Can it be something obscure and unrelated?
    • Of course it can, it’s Nginx. It’s very customizable. 🦚
    • This can be done by simply adding a add_header Server <server-name> directive. I named mine Cloudflare because why not. 🤷‍♂️
server {
	...	
	# Dontshowtheversionofnginximscaredofgettinghacked
	server_tokens off;
	add_header Server "Cloudflare";
	...
}
  • Reload nginx.
third_response
Why are there two Server headers!?

Now it should look like it’s being routed through Cloudflare. Right?

well-yes-but-actually-no

  • Why are there two Server headers? Is that even possible? Turns out, it is.

  • There are standard headers that Nginx might include in responses depending on the configuration and situation. Server is among them. Now that we know that, we have to find a way to remove the Server header set by nginx.

  • After some searching, I discovered that the more_clear_headers directive, available in the nginx-extras package, can accomplish this task. Although I prefer to avoid installing additional dependencies, this appears to be the simplest solution I can find right now. Installation instructions are available for reference. Once you have set up the repository configuration, the specific Nginx module required for this functionality is known as nginx-module-headers-more.

    • And then add the more_clear_headers Server directive to your server block.
server {
	...	
	# Dontshowtheversionofnginximscaredofgettinghacked
	server_tokens off;
	add_header Server "Cloudflare";
	more_clear_headers Server;
	...
}
  • Reload nginx.
  • Looks like it’s finally working. :)
fourth_response
It now looks like Cloudflare is our server when it’s really not.

clapping

Note:

  • But wait! One more thing. Don't forget to create custom error pages, too, because Nginx happily displays the version it's currently running on these pages too. 403_forbidden
  • Cloudflare's Server headers actually return cloudflare and not Cloudflare. At least that's what it did during the time of writing this article but I am too lazy to change the screenshots. 🤷‍♂️
  • Now you’re a tiny bit safer on the internet. Obviously don't take this as a replacement for proper security practices. This is simply a way to make it a bit harder for attackers to find out what you're running.

Adios! 🐄