IIS 7 – How to send a custom "Server" http header

A question we have often seen in the past is to have a method to prevent IIS from sending the server identification header to a client which allows a client to identify which type of http server it is talking too. Usually this request comes from security concerns as knowing the server would allow a hacker to more easily be able to break into the system.

Although the above assumption from customers is very doubtable we still need to be able to provide a solution for this.

Out of the box all our IIS servers respond with a server header similar to the following (sample is for IIS 6.0):

Server: Microsoft-IIS/6.0

For IIS 5 and IIS 6 customers often used UrlScan which allows to remove the server header from the response.

On IIS 7 this tool cannot be installed – but due to the very modular structure of IIS 7 it is possible to remove or even replace the Server header in a much more convenient way: using a custom Module which is injected into the IIS 7 Pipeline. Such a module can be developed as well using managed or unmanaged code.

Here is a sample .Net module which replaces the server http header with a custom header:

using System;
using System.Text;
using System.Web;

namespace StefanG.ServerModules
{
    public class CustomServerHeaderModule : IHttpModule
    { 
        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += OnPreSendRequestHeaders;
        } 

        public void Dispose()
        { } 

        void OnPreSendRequestHeaders(object sender, EventArgs e)
        {
            // modify the “Server” Http Header
            HttpContext.Current.Response.Headers.Set(“Server”“Stefan’s Webserver”);
        }
    }
}

That’s it! When generating this module ensure to strong name it as it needs to be placed into the global assembly cache in order to allow IIS 7 to use it. To add the module to IIS 7 use the “Modules” configuration option on the server, choose “Add managed module” and select the module from the list of available modules.

19 Comments


  1. I think that this is a really good idea, and is a good idea to include as standard.

    Reply

  2. Excellent.  I’ve just migrated to IIS7/WS2008 and this will be one of the modules I use.

    Reply

  3. Actually, you don’t need to put this module in the GAC to make it work.  You can actually just copy + paste the code above into a file named "CustomServerHeaderModule.cs" and put it into a directory named "App_Code" off of your site root, or application root, register the module in your Web.config as follows:

    <configuration>

    <system.webServer>

    <modules>

    <add name="CustomServerHeader" type="StefanG.ServerModules.CustomServerHeaderModule" />

    </modules>

    </system.webServer>

    </configuration>

    or in the UI and it will work for that site / application immediately.  (this approach is obviously not recommended for production deployments, but it is kind of fun and easy to test).  For a more performant solution, compile the CustomServerHeaderMdoule.cs into a module.dll, and put it into the bin directory of your site/app.  This method allows every site / app to modify the server header in their own custom way.  

    Of course, who would try to hide the fact they are running IIS7 anyway. 😉

    Reply

  4. Hi Bill,

    sure you are right. The method with the GAC allows a more centralized way to control this. A more flexible solution might be to read from the desired header to set from the web.config file of the web app.

    And I also agree with your last sentence. 😉

    Cheers,

    Stefan

    Reply

  5. This would have been trivially easy to add to the default build of IIS7.  Microsoft deliberately chose not to do so.  They don’t want people to change the Server header because of NetCraft and other Internet-wide inventories of web server versions.  Microsoft wants IIS to be as widely identified as possible in these inventories for marketing purposes.  Once again Microsoft sacrifices our security to their marketing plans.  Thank you Microsoft for looking out for us…

    Reply

  6. Hi Not Eric,

    assuming that hiding the server header will give you any improvement in security is dangerous.

    Someone really interested in hacking your system will not be hold off through this.

    I personally think that hiding this name gives users a wrong feeling of security which might even cause more problems.

    Cheers,

    Stefan

    Reply

  7. Hi Stefan:

    Thank you for your reply.

    Changing the Server response header does help to prevent showing up on scan lists which are targeting a particular make/model of web server.  For example, a worm might be designed to only attack servers with a particular Server response header, or if a hacker is using Server headers to compile a list of servers of a particular type from a given IP range, then it would be better to not show up on that list.  

    It’s true that changing the Server header won’t fool a hacker for more than a second who is out to get your site in particular, but not all adversaries are out to get your site in particular, some are just scanning (using Server headers and other fingerprinting methods) to find any random site that meets certain criteria.  

    I agree it’s a minor issue, but in comparison with how absolutely trivial it would have been to add the ability to change the Server header when so many people ask about it (case in point, your post) it undermines Microsoft’s claims about really caring about our security when they don’t add it for the sake of a slight marketing benefit.

    You might think I’m a Microsoft-basher, but I posted this for a reason: real Microsoft-bashers LATCH onto things like this, so why give them the opportunity?

    Best Wishes, NE

    Reply

  8. Anybody scanning servers looking for a particular type would be using one of the many security tools which identifies a server by the structure of it’s TCP response.

    So in actual fact, removing the server header is useless in preventing people from identifying your server’s OS, etc.

    However, it’s still something you definately want to be able to remove, so thanks for your solution for this.

    Reply

  9. I support the removal of the Server HTTP response header by default, and Microsoft should have allow it to be disabled in the UI.

    We know it’s not a fool-proof security measure, but I believe that one-extra hoop for a worm to jump through will make my box more secure than that of people with the Server response still intact.

    My interest here however, is cutting down on bandwith as much as possible.  I run high demand sites, the bandwith used to tranfer "Server: Microsoft-IIS/7.0" with EVERY request, for the millions of users served, the real cost to us by our ISP for transfering this is very high. (An extra gigabyte after 47million requests, gigabytes transfered cost money).

    Reply

  10. When adding this module to web.config it is still possible to find the server software.  Telnet to your HTTP server, and press Ctrl-C.  The following response is sent (from IIS/7.5):

    HTTP/1.1 400 Bad Request

    Content-Type: text/html; charset=us-ascii

    Server: Microsoft-HTTPAPI/2.0

    Date: Tue, 28 Jul 2009 14:47:07 GMT

    Connection: close

    Content-Length: 326

    … HTML content saying: HTTP Error 400. The request verb is invalid.

    Has anyone tried this after installing the module in GAC?

    Reply

  11. Additionally I’ve added code to OnPreSendRequestHeaders:

    HttpContext.Current.Response.Headers.Remove("X-AspNet-Version");

    Without removing the X-AspNet-Version you’re identifying yourself as most likely running IIS version 5 or above, since ASP.NET doesn’t run on IIS 4.  I’m unsure if mod_mono for Apache would add the X-AspNet-Version header.

    Reply

  12. Remark on Corey’s post:

    indeed responses created by IIS kernelmode component HTTPSYS cannot be customized.

    Reply

  13. Hi,

    Thanks for this article. One question:

    I would like to remove one of the Set-Cookie headers that have been added to the response before it is sent back to the client. If I use repsonse.headers.remove("Set-Cookie"), then I guess all Set-Cookie lines will be removed. I cannot find a remove(index) method. Help appreciated!

    Thanks,

    Mats

    Reply

  14. I know, but I want to eliminate the cookie from the response altogether as passing it to the client would mean a security issue.

    Reply

  15. Hi Mats,

    I don’t know if this is possible.

    Cheers,

    Stefan

    Reply

  16. Thanks for the great post. One thing I noticed is that the latest URLScan (its current version is 3.1) is actually working on both IIS 7.0 and IIS 7.5. So we can simply add RemoveServerHeader=1 in URLScan.ini configuration file, if our goal is just to strip the server information from the header completely.

    Thanks,

    AMB

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.