New technologies: HAProxy!

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 catalogued these remediation instructions for many technologies in this single site to save the vast amounts of searching required for some of the more obscure technologies. Instructions for both load balancers/proxies and individual application servers are provided. Both a short solution and a longer one giving more details along with alternate and (perhaps) more thorough corrective actions is provided. This page is periodically updated (though the timestamp may not change).

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 generated many technologies is presented here. If you have other headers that keep popping up and would like them documented on this blog, pass them along to me to publishing. Remember, “Defense in Depth”™ – if you use multiple chained servers (e.g., F5 → nginx → Tomcat), you should remove the headers at each level. Major technologies groupings in this document are:

  • Proxy, Tunnel, Router, & Load Balancer
  • Unix native servers
  • Java
  • JavaScript
  • PHP & Ruby technologies
  • Firewalls, Load Balancers, WAFs, & Other Weirdness
  • Microsoft technologies

See the Table of Contents for the full list of headers and technologies presented.

Proxy, Tunnel, Router, & Load Balancer

Rather than hooking application servers up directly to the web ports, various proxies and tunnels are used on the front-end. For example, Tomcat may live on port 8080 and only listens for localhost connections while Apache handles ports 80 & 443 and will directly serve static pages, handle TLS, and only pass along the jsp/servlet requests to Tomcat. This reduces load on Tomcat while also speeding up the machine since Apache is faster than Tomcat (yes, even with super-advanced JIT, Apache is still a little faster). Thus, here are some common configurations for the front-end proxy / tunnel / load balancing server which removes the headers from the upstream servers.

Configurations are provided for Apache and nginx in Proxy mode and FastCGI mode. I’d appreciate hints on HTTP.SYS for IIS from any readers. The kHTTPd and Tux servers (and similar Solaris and HPUX kernel servers) are effectively dead, so no advice is provided here.

As the servers can front-end disparate technologies, such as Apache load balancer in front of an ASP.Net farm, consider removing headers in both locations for Defense-in-Depth. Even if the current technology stack does not involve all headers, add them anyway. You never know what developers may do in the future. Use the IIS configurations elsewhere in this document while also adding directives to Apache to remove them on the front-end. Thus, consider simply adding removal directives for all of these headers:

  • Server †
  • X-Powered-By
  • X-AspNetMvc-Version
  • X-AspNet-Version
  • X-Drupal-Cache
  • X-Drupal-Dynamic-Cache
  • X-Generator
  • X-Runtime
  • X-Rack-Cache

† Remember that Apache and nginx running in proxy mode still adds the Server header on their own even if removed from upstream servers. You will need to configure the servers itself separately per elsewhere in this blog post.

HAProxy as a Router

Short Answer

Add this to HAProxy’s config:

Long Answer

Using HAProxy’s del-header command will allow a mass deletion of the insecure headers, for example:

For an alternate solution, you could use the rspidel command to delete whole header lines as a regular expression with something like this:

nginx as Reverse Proxy

Short Answer

When using nginx as a proxy, use proxy_hide_header in nginx.conf to remove the header:

Long Answer

nginx can be used as a proxy to send traffic to another listener, such as a NodeJS instance. As part of the configuration, proxy_hide_header can be used to remove headers set by the upstream server. Here is a sample nginx.conf file demonstrating the removal of the many server headers from the upstream server:

Apache as Reverse Proxy

Short Answer

For Apache as a proxy, use mod_header’s Header unset in httpd.conf to remove headers:

Long Answer

Apache is sometimes used as proxy to forward traffic to load balancers or a running Tomcat (or other) server instance. As part of the configuration, the Apache module mod_header’s Header unset directive can be used to remove headers set by the upstream server. Here is a sample httpd.conf file demonstrating the removal of several headers from the upstream server:

nginx with FastCGI

Short Answer

When FastCGI runs with nginx, use fastcgi_hide_header in nginx.conf to remove the header:

Long Answer

nginx can be combined with FastCGI to forward requests to another listener, such as a PHP or NodeJS. The fastcgi_hide_header command can be used to remove headers set by the upstream server. Here is a sample nginx.conf file demonstrating the removal of many headers from the upstream server:

Squid as Reverse Proxy / Accelerator

Short Answer

When using Squid in reverse proxy mode, add these lines:

Long Answer

Most of the time, Squid is used as a proxy for user activity, such as in a corporate single egress configuration or for a user who just wants to reduce advertisements by having Squid filter them out. However, Squid can also by used as a reverse proxy or content accelerator/cacher much like Apache or nginx or F5 could be implemented. As such, add these settings to the Squid configuration:

F5 BigIP as Proxy

Use the HTTP::header remove rules inside of when HTTP_RESPONSE to remove the insecure header. For example:


Server: Apache/2.2.x …

Short Answer

Set these in httpd.conf:

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:

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:

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

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:

Long Answer

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

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:

Or even set a custom server header, like so:

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


Server: Apache-Coyote/1.1 & X-Powered-By (Tomcat)

Short Answer

In $CATALINA_HOME/conf/server.xml, add addributes xpoweredby="false" and server=" " to <Connector> as follows:

Long Answer

It is not possible to completly remove the Server header from Tomcat/Coyote, but you can set the value to something else. It must be at least one character, like a space, otherwise static files like images or CSS will still transmit “Server: Apache-Coyote/1.1”. To modify, edit the $CATALINA_HOME/conf/server.xml configuration file and add an attribute called server to <Connector> and set a value.

Tomcat disables X-Powered-By by default; but if the header is showing up, add the attribute+value xpoweredby="false" to the <Connector>. However, we recommend to always add the setting just in case.

Overall, the settings may look like:

It is possible to use a fake value, like server="Microsoft-IIS/8.0" for a server header.

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:

$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:

Server: Glassfish & X-Powered-By: Servlet/3.0 JSP/2.2

Short Answer

For the Server header, add a flag to the JVM options or command line:

For X-Powered-By, add this to web.xml:

Long Answer

A detailed explanation of the above is provided on the Bistro 2.0! blog (new URL, sigh, Oracle

X-Powered-By: Servlet 2.x; JBoss-4.x / JBoss-5.x

Short Answer

Edit web.xml and remove the <context-param> setting for “X-Powered-By”. Basically, delete this:

Server: Jetty(9.x.x…)

To remove Jetty 9.x’s Server header while running in standalone mode, add this to start.ini:

Server: Jetty 8.x & 7.x

To remove Jetty 8.x’s or 7.x’s Server header while running in embedded mode, instantiate the server with the follow lines of code:

The solution is a little more verbose when running Jetty in standalone mode. The following is to be added to jetty.xml and this code should disable the Jetty header. However, this configuration has not been tested by me, it is theoretical (someone confirm and get back to me).

Nevertheless, if you’re using Jetty 8.x, it is end of life and you should consider upgrading to Jetty 9.x or newer.

X-Powered-By: JSF/1.2 — Mojarra and others

To remove X-Powered-By in JSF applications, add this to web.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:

Another option for security plug-in is Lusca, which is similar to Helmet.

Long Answer

In Express 3.0 or newer, there are two means:

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

However, the Helmet security package can both remove this header and enable many other security features, such as clickjack prevention, some XSS protection, secure caching controls, etc. All by adding this:

For more information on Helmet, see For another option, you can use the Lusca software instead of Helmet.

PHP, Ruby, & Friends

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:

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:

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

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.

X-Drupal-Cache, X-Drupal-Dynamic-Cache, X-Generator

Long Answer

Drupal installations can produce a few headers with security consequences, including unnecessary caching headers and a detailed version number inside of a “X-Generator” tag. Sending these headers to an end-user browser serve no purpose other than debugging – so remove them. The headers might be needed for caching proxies; so ensure the proxy engine strips the headers. Drupal can also send X-Powered-By, but that is usually caused by the underlying PHP system (see above).

To remove the X-Generator head, install the module, “Remove META and Headers” from here. Be warned that there are some issues with some versions of Drupal, so your best bet might be to implement the code manually.

There is no native mechanism to remove the X-Drupal-Cache & X-Drupal-Dynamic-Cache that I can discover. Drupal modules like Security Kit and HTTP Response Headers referenced from Chapter Three’s blog add good security headers but do not remove bad ones generated by Drupal. Thus, additional software tools like an Apache or nginx proxy are required.

X-Rack-Cache, X-Runtime (Ruby on Rails)

Long Answer

Ruby on Rails can add “X-Rack-Cache” or “X-Runtime” depending on your setup. These unneeded headers can be removed using the Rack middleware as part of your Rails application. As suggested by Cascadia Enterprise, in application.rb, configure a new function to run during the processing chain by calling config.middleware.insert_before:

And ensure that HeaderDelete class is defined somewhere in your application:

Note that Apache, nginx, and other middleware may add additional downstream Server and X-Powered-By headers that Ruby on Rails will be unable to remove. In those cases, refer the appropriate sections elsewhere in this document to remove. It may also not be possible to remove X-Rack-Cache in some instances, so Apache or nginx proxies will be needed.

Firewalls, Load Balancers, WAFs, & Other Weirdness

This section contains configurations for when the device itself adds insecure headers. The previous load balancer section discussed how to configure the tunnel to strip the headers added by other servers.

Server: BigIP

Short Answer

Add noserver to the 302 rule:

Long Answer

Generally, we see this when the server is doing a redirect from HTTP to HTTPS and in no other requests. So, adjust the 302 redirect rule by adding noserver where appropriate. For example:


The Runtime header is used by many frameworks to show how the CPU time or Wall time for a request. This may seem innocuous, but this type of data can be used for various timing attacks such during authentication / password validation. The mechanism for removal is framework dependent, but the most common source is Ruby on Rails discussed above or use Apache or nginx in proxy mode to strip it out.


At the bottom of this section, there is a combined configuration to correct all of the exposed Microsoft headers presented here.


Short Answer for IIS hosted on Azure’s cloud

For Azure, add this to the configuration:

For local installs of IIS, there really isn’t a short answer, so…

Long Answer for locally-hosted or other IIS

There are two solutions from Microsoft, both of which are not quick or simple: use URLRewrite or use URLScan. These solutions are described in Microsoft’s technical blog at remove-unwanted-http-response-headers in the first section.

A third solution is to use the IIS Strip Headers module found at This is a native-code plug-in for IIS that can remove the headers from IIS 7.0 until 8.5. It also has the ability to remove some of the other headers mentioned in this document.

However, as with the minimalistic Apache header, sometimes the complete solution is not worth the extend effort since a very determined attacker will be able to figure out the version of IIS using specialized software fingerprinting.


Short Answer

Add this to the registry:

Long Answer

If the system is running self-hosted WCF, then using the tricks for IIS will not remove this header. Thus, edit the registry key HKLM\SYSTEM\CurrentControlSet\Services\HTTP\Parameters and add/edit DisableServerHeader to be a DWORD with value of 1. Or, simply run this registry file:

However, if registry editing is not allowed, then try something like:

X-Powered-By: ASP.NET

Short Answer

Add this to your web.config:

Long Answer

With the presence of WebResouce.asdx and *.aspx file on a website, the use of .Net is fairly obvious. However, the fairly long string of 22 known characters may aid attacks against a TLS connection. Thus, it is probably best to remove the header.

There could be cases where the above does not work. In those situations:

  1. Open the IIS console.
  2. Choose the web site.
  3. In the IIS section, click on HTTP Response Headers.
  4. In the Actions Pane, choose “X-Powered-By” and delete it.

X-AspNet-Version: 4.0.detailed.version

Short Answer

Put this in web.config:

Long Answer

The X-AspNet-Version header gives the patch-level of .Net installed and makes it much easier for an attacker to determine vulnerabilities in libraries on the server. To remove, add this to web.config:

X-AspNetMvc-Version: 3.x

Short Answer

In Global.asax.cs, this to Application_Start() :

Long Answer

In the application’s Global.asax.cs file, add this to the Application_Start() function to disable the header:

See the reference URL below for more a thorough description of this code.

Overall IIS or ASP.NET web.config suggestions

Other Resources and Credits and references

Most of the knowledge in this page has been collected from old reports and generally known concepts over many years. However, some items were researched again and particularly well written documentation needs to be given credit. Thus, I thank those authors:

This blog post was once mirrored on the Aspect Security blog as official advice for remediation, but that link no longer works after Aspect Security was purchased.

About The Author

This blog post was written by Jay Ball and published on Jay’s blog at Jay is an #infosec professional who does penetration testing, security threat modeling, security compliance, security architecture, and security whiskey in many of the skyscrapers throughout Manhattan and Jersey City. He participates in local infosec organizations such as OWASP, 2600, HackNYC, and more. You can reach Jay via DM on Twitter @veggiespam or via email.