Aspect Security's AppSec Blog

Insecure HTTP Header Removal

Posted by Jay Ball

Find me on:


 *The original and updated version of this post can be found here, on Jay Ball's personal blog. 

This page is a collection of instructions to remove unnecessary server headers which may be reported as part of a Penetration Test performed by a security engineer or reported via automated tools. I have cataloged these remediation instructions for many technologies in one place to save the vast amounts of searching required for some of the more obscure technologies.

Each section below is be divided into a short solution and along with a longer one. The “Short Answer” gives the quick means to remove the offending header while the “Long Answer” gives more details along with alternate and (perhaps) more thorough solutions.

Why bother? In general, excessive headers are bad:

  • They expose what version of software is running on the server, reducing the work an attacker needs to do before trying to attack the system.
  • Headers are the same for a normal user or an attacker. So, a known long string of characters in an encrypted data stream might aid an attacker in cracking open the encrypted TLS connection of another user.
  • It’s a general waste of bandwidth and processing power.

The solution for many headers is presented here. If you have other headers that keep popping up and would like them documented on this blog, pass them along through the comments. 

Table of Contents


Server: Apache/2.2.x …


Short Answer

Set these in httpd.conf:

ServerTokens  Prod
ServerSignature Off

Long Answer

Apache’s Server header ranges from the ultra detailed ‘Server: Apache/2.2.15 (CentOS) DAV/2 PHP/5.3.3 mod_ssl/2.2.15 OpenSSL/1.0.1e-fips Phusion_Passenger/4.0.59 mod_perl/2.0.4 Perl/v5.10.1’ to the simplistic ‘Server: Apache’. It is best to use the minimal version. To configure, add this to httpd.conf or equivalent file:

ServerTokens ProductOnly    # (... or just "Prod")
ServerSignature Off

These two options will reduce the Apache identification to just “Apache” with no version indicators. Both work for Apache 1.x and 2.x.

To fully remove the header, one option is to modify the code and compile the server to completely remove the server header. This is a bad idea as your organization will now have the added responsibility of patching the code each time there is a security update. It is best to rely on your Apache vendor’s packages for your patch management.

Another full-removal mechanism is to use mod_security’s SecServerSignature to modify the Server header value value with something like:

SecServerSignature "Microsoft-IIS/8.0"

A third option is to use mod_headers and modify the Server header directly in httpd.conf with something like:

Header set Server "Microsoft-IIS/8.0"
## or, even remove the header with this next line
## Header unset Server

However, it should be noted that the fact Apache is used can be ascertained via other means and fingerprinting techniques. For example, Apache sets the Date header in a different spot in the HTTP header list than IIS will send it. There are also various TCP handshake tricks that can be done to determine the Operating System (e.g., IIS on Linux will tip off a determined attacker). The fact that a system uses PHP probably means that Apache or NGINX are being used anyway. So, removing the Server header completely via the complex means above is not worth the trouble.

Server: NGINX/1.8.x


Short Answer

In nginx.conf, add this line:

server_tokens off;

Long Answer

Edit the nginx.conf configuration file add a server_tokens off line in the top level of the file:

listen 80;
server_tokens off;
## ...

Like Apache, setting server_tokens off will remove the version of NGINX but not that fact that NGINX is being used. To further remove the header, it is possible to re-compile the code with a new header.

Another option is to use a module called “ngx_headers_more”. This NGINX add-on allows for more control over the Server header. So, to delete the Server header, add this to the nginx.conf:

more_clear_headers Server;

Or even set a custom server header, like so:

more_set_headers 'Server: Microsoft-IIS/8.0';

Be sure to dynamically load the module or to re-compile the server as required per the version of NGINX.

X-Powered-By: PHP/5.x.x …


Short Answer

Add or modify the php.ini to set the expose_php variable to off, like so:

expose_php = Off

Long Answer

PHP headers give away the version, patch level, and more in something like ‘X-Powered-By: PHP/5.1.6-3+b2’. It is best to remove this exposure by changing the php.ini configuration to shut this off. So, modify the php.ini file and set the ‘expose_php’ variable to off like this:

expose_php = Off

Another option is to use Apache’s mod_headers to disable the header with something like:

Header unset X-Powered-By

The principle of “Defense in Depth” might mean you do both, just in case someone forgets to disable the variable on a server, but in general, modification of the variable is sufficient.

Java-ish & JavaScripty

X-Powered-By: Servlet/3.0 (WebSphere 8.5.x and others)


Short Answer

Set the property to true.

Long Answer

The best solution is to set the property to true. It is possible to modify X-Powered-By via the to a value such as ‘PHP/5.1.6-3+b2’. But, this is not recommended – just disable it.

Another option, if using the IBM HTTPd Server along with WebSphere, is to configure the server to unset the X-Powered-By header via mod_headers. Since IBM HTTPd Server is really Apache, use the same technique as shown above with Apache, mod_headers, and PHP:

Header unset X-Powered-By

$WSEP (WebSphere proxy request)


Short Answer

Add this property to server.xml:


Long Answer

The $WSEP header is generally produced when the WebSphere Application Server is performing some type of proxying action during a request or response. However, we have observed it in situations where the server owner was not aware of any proxy configuration. To disable the appearance of the header, add this property to server.xml:


X-Powered-By: Express


Short Answer

For Express 3.0 or newer:


However, for a more thorough (and highly recommended) solution, just use Helmet instead:

In Express 3.0 or newer, there are two means:

// option 1:
// option 2:
app.set('x-powered-by', false); 

For older versions of Express, you need to write middleware that removes the header:

Topics: Application Security, Vulnerabilities, Insecure HTTP Header Removal