The purpose of this blog post is to discuss how to mask an IIS server’s IP address from being sent as part of an HTTP response. By default, IIS can send a server’s IP address in the Content-Location or Location response headers of a response. Beginning in Windows 2003 SP1, you can configure IIS to behave differently. The release version of IIS7 by default includes the functionality of masking the IP address.
What are the Content-Location and Location headers?
The HTTP specification defines the Content-Location and the Location headers. You can find the exact definitions at www.w3.org. For Content-Location, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14, and for Location see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30. In short, however, the Content-Location and the Location headers are sent by an HTTP server as part of its response to an HTTP request, and contain location information for the resource that the client requested.
Why is sending the IP address bad?
Telling a client where its requested resource resides is an integral part of a the HTTP request/response cycle. The problem with sending location information as part of the response, however, is that in some cases that location information could reveal more to end-users than is necessary for the user to get the web page they’re looking for. It is not uncommon for security scanning tools to check for IIS sending sensitive info in the Content-Location or Location headers. The most common type of “extra info” that security scanning tools may flag as insecure is the IP address of the IIS web server. By default in Internet Information Services 6.0, a server’s IP address is sent as the location.
If you use a security scanning tool to check the security levels of your IIS web server and it alerts you that IIS is revealing the server’s IP address in the Content-Location or Location headers, or if you just want to proactively lock down your IIS server in this regard, you can make a configuration change in IIS to resolve this. Making the config change is a two-step process: install Windows Server 2003 sp1 or later, and then set either the SetHostName or UseHostName metabase properties. These steps are outlined in detail below.
Using SetHostName/UseHostName in Internet Information Services (IIS) 6.0
1) To begin with, an update to IIS 6 was made to allow this configuration changes to be made. This update is described in the following KB article:
FIX: IP address is revealed in the content-location field in the TCP header in IIS 6.0
You will need to install this update package before proceeding. If your IIS6 web server is running Service Pack 1 or later for Windows Server 2003, the update is already installed on your server.
It is also very important that you install the following additional update:
FIX: The IP address or the host header of the server that is running IIS may be returned unexpectedly when you use the Request.ServerVariables collection in IIS6
This update addresses a known issue that resulted in the KB834141 update being ineffective in certain conditions.
2) The next step in the process is deciding what information you want IIS to send in the Content-Location and Location header fields in HTTP responses. The update package provides you two options to choose from. You can choose to set a custom hostname that IIS will send instead of the IP address, or, you can choose to have IIS always send the fully qualified machine name. It is important to note that you must choose ONE of these options; you cannot have both options in use at the same time for the same web application.
3) Once you decide which option to use, it is time to put the appropriate configuration changes in place by using the adsutil.vbs tool, which is included with IIS. If you want IIS to send a hostname of your choice in the response header, you will need to configure the SetHostName metabase property. The SetHostName property is a string, and you can set it as follows:
C:\Inetpub\AdminScripts> cscript.exe adsutil.vbs set w3svc/1/SetHostName MyIISserver
In this example, the number 1 is the ID number of the site that is getting configured, and MyIISserver is string that will be sent in the response header. The output of running this command should look like the following:
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
SetHostName : (STRING) "MyIISserver"
Alternately, if you want IIS to send the server’s fully qualified machine name in the Content-Location and Location response headers, you will need to configure the UseHostName metabase property. The UseHostName property is a Boolean value or true or false, as the following example shows:
C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set w3svc/1/UseHostName true
The output of the command should look like this:
UseHostName : (BOOLEAN) True
Remember that you need to set either the SetHostName or the UseHostName properties, but not both. The SetHostName property will cause IIS to ignore the UseHostName setting. You do not have to set the UseHostName property if the SetHostName property is present.
Setting the hostname in Internet Information Services (IIS) 7.0
The configuration property to set the hostname in IIS 7.0 is not the same as in IIS6. In IIS7, there is just one property, named alternateHostName. You can use this property to set whatever hostname you wish, be it the machine’s FQDN or otherwise. To set this, you can use the command-line utility appcmd.exe. Here is an example command to set a hostname of “myServer”:
appcmd.exe set config -section:system.webServer/serverRuntime /alternateHostName:"myServer" /commit:apphost
NOTE: The SetHostName and UseHostName properties will only be used in the server's response if the client's request does not include an HTTP:Host header value. If the client's request does contain a Host value, then the server's response will use that value in the Location or Content-Location header fields. Keep in mind that this means if the client uses the server's IP address for its HTTP:Host header value, then the server's response will contain that IP address in the response, regardless of if SetHostName or UseHostName are set.
After setting the UseHostName or SetHostName properties in IIS6, or the alternateHostName property in IIS7, it is still possible to see the server’s IP address sent in an HTTP response. This will not happen by default, but instead is a result of how the response is being generated and sent.
1) If you configure an HTTP redirect that results in an HTTP 302 response being sent, and your redirect code uses the server’s IP address, then the IP address may appear in the Content-Location or Location header of the response. To work around this issue, do not use the server’s IP address in the redirect logic; instead, use its host name or fully qualified machine name. A similar type of behavior can occur if you configure custom error pages to perform a redirect, and you use the IIS Manager to set the redirect target as a URL instead of a File. In this scenario, specifying the File instead of URL will keep the IP address hidden.
2) Another known issue is the one described in KB935469, which was called out earlier in this blog post. It is very important that this hotfix is installed on your IIS servers!
3) If an HTTP request that does not include an HTTP:Host header value is sent to IIS, and there is an ISAPI filter configured in IIS that makes a call to GetServerVariables(servername) during the SF_NOTIFY_PREPROC_HEADERS event, the IP address will always be returned instead of the server's hostname (or the value set in SetHostName). This is because PREPROC_HEADERS is called before IIS has read the configuration data (in this case either UseHostName or SetHostName), therefore there is no other choice but to return the IP address. Note that this behavior only occurs if the HTTP request doesn't send an HTTP:Host header value; if the request contains a Host value, then SERVER_NAME will contain the value of the client's Host header. Web browsers using HTTP/1.1 are not supposed to omit the Host header value, so this scenario is much more likely to be seen where the HTTP request is generated and sent by something other than a web browser (or if a web browser is using HTTP/1.0)