Troy Hunt is a Microsoft MVP for Developer Security and regularly blogs and tweets about security principles. He is the creator of ASafaWeb, the Automated Security Analyser for ASP.NET Websites. Troy has observed that around 67% of ASP.NET websites have serious configuration related security vulnerabilities. ASafaWeb makes scanning for these vulnerabilities dead easy and provides both remediation and additional reading around the resolution.
Troy blogged about excessive response headers in Shhh… don’t let your response headers talk too loudly.
By default, an ASP.NET application running on IIS returns a lot of information about the server and framework via the headers. This information can be used to help exploit vulnerabilities that are present in the technologies the headers identify. If any of the following response headers are returned, ASafaWeb will report a warning for this scan:
I set off to discover how to remove this configuration vulnerability from an ASP.NET Web API application running on Windows Azure.
Create a simple ASP.NET Web API application
Start Visual Studio 2012 as Administrator (we’ll need elevated privileges later when running the Windows Azure Emulator).
Create a new project with File > New > Project and select ASP.NET MVC 4 Web Application. Give the project a name of WebAPI and the solution a name of ExcessiveResponseHeaders. Click OK. Select the Web API template and click OK.
Right click on the WebAPI project in the Solution Explorer and select Add Windows Azure Cloud Service Project. A WebAPI.Azure project will be created with a WebAPI Role associated with the WebAPI Project. The WebAPI.Azure project will be configured as the startup project.
The default Web API project created by Visual Studio will contain a simple Values Controller. Throughout this post I’ll be using the GET api/values REST endpoint which will simply return a list of 2 strings [ "value1", "value2" ].
Hit F5 and start up the project in the Windows Azure emulator.
Removing the Headers
Using Fiddler and issuing a GET api/values to the WebAPI application running on the Windows Azure emulator we can observe the following response headers:
- Server: Microsoft-IIS/8.0
- X-AspNet-Version: 4.0.30319
- X-Powered-By: ASP.NET
No X-AspNetMvc-Version response header is observed since the api/values route is being managed by the WebAPI framework. If you issued a GET to the following URL: http://127.0.0.1:81/a/a you would observe the MVC header as the MVC framework routing would be brought into play:
To remove the Server header we add the following method and code to the Global.asax.cs file in the WebAPI project:
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
To remove the X-AspNetMvc-Version header we add the following code to the Application_Start() method in the Global.asax.cs file in the WebAPI project:
MvcHandler.DisableMvcResponseHeader = true;
To remove the X-AspNet-Version header ensure that the Web.config has the following xml:
<httpRuntime enableVersionHeader="false" />
To remove the X-Powered-By header ensure that the Web.config has the following xml:
<remove name="X-Powered-By" />
Hit F5 in Visual Studio again to start up the application with our changes. Using Fiddler and submitting a GET api/values to the WebAPI application now shows that the headers have been suppressed.
Deploying this code to Windows Azure (http://pbwebapi.cloudapp.net) confirms that this solution works there too.
In Azure running the default Web API solution (before suppressing the headers):
In Azure running the modified Web API solution (after suppressing the headers):
Is there a NuGet package for that ?
There always is … And its name is NWebsec.
Revert all the changes made previously in the Global.asax.cs and Web.config files. Right click on the WebAPI project and select Manage NuGet Packages … Search for NWebsec and install.
The installation of the NuGet package modifies the Web.config in the WebAPI project by adding a nwebsec sectionGroup and an entry in modules.
The X-Powered-By header is added by IIS and cannot be removed in the processing pipeline. Therefore NWebsec cannot remove it. To remove the X-Powered-By header ensure that the Web.config has the following xml:
<remove name="X-Powered-By" />
To suppress all the other headers ensure that the Web.config contains the following xml:
<suppressVersionHttpHeaders enabled="true" />
That was much better. We only had to add some configuration to the Web.config. There was no code involved.
The NWebsec package does not suppress the Server header but defaults it to a value of Webserver 1.0 – this value can be configured in the Web.config. All other headers are suppressed as can be seen via Fiddler.
Once the update is deployed to Azure (http://pbwebapi.cloudapp.net) it is confirmed that this solution works there too.
Scanning with ASafaWeb
Scanning the api/values REST endpoint of our default Web API application via the ASafaWeb analyser returns a warning about the same headers we observed via Fiddler.
Scanning the api/values REST endpoint of our NWebsec enabled Web API application via the ASafaWeb analyser returns a warning about the same headers we observed via Fiddler.
Scanning the api/values REST endpoint of our manually configured Web API application via the ASafaWeb analyser returns a warning about a Server: Microsoft-IIS/8.0 header. This is not what we observed via Fiddler.
But wait … What is that URL that is being scanned ?
Sneaky ! That URL was resulting in a 404 being raised by IIS since the file did not exist. This was bypassing the processing pipeline and our attempts to suppress the headers.
Closing the 404 – Not Found hole
We’ll be continuing with the manual version of our suppressing headers code – I’m aiming to suppress all headers and the NWebsec package still sends down a Server header.
Again there is a NuGet package that comes to the rescue. NotFoundMVC automatically installs itself during web application start-up. It handles all the different ways a 404 HttpException is usually thrown by ASP.NET MVC. This includes a missing controller, action and route.
Right click on the WebAPI project and select Manage NuGet Packages … Search for NotFoundMVC and install.
The NotFoundMVC package will make the following modifications to the Web.config file in the WebAPI project. The Error.cshtml placed under Views\Shared may be modified to provide customised 404 pages.
Deploying to Azure and scanning the api/values REST endpoint of our manually configured Web API application via the ASafaWeb analyser returns a PASS.
But wait – there’s more …
You’d think I would be happy with the PASS ! But I had seen something in one of the URLs attempted by the ASafaWeb analyser. It had thrown in an illegal character into the URL. So I tried the following URL locally:
Why is that Server header back ? And why is it now reporting Microsoft-HTTPAPI/2.0 ?
When you see a Server header value containing Microsoft-HTTPAPI instead of the IIS version it means the HTTP.SYS driver handled the request and it did not traverse all the way to the IIS user mode process.
So how do we get rid of that header now ? This header is being added right down at the kernel level. Time to break out the trusty regedit utility. Add a DisbableServerHeader REG_DWORD with a value of 1 to the following:
This requires the HTTP.SYS service to be restarted. I battled with service dependencies but a reboot of my machine ensured the restart. Once that was done, the illegal URL no longer exposed the Server header.
And finally – modifying HTTP.SYS in Windows Azure
Trying the URL with the illegal character produced the same result in Windows Azure.
To edit the registry on the web role in our cloud service in Windows Azure we’ll need to write a batch file. Right click the WebAPI project and click Add > New Item … Add a Text File with name Configure_HTTP.SYS.cmd and populate with the following:
reg query "%regpath%" /v "DisableServerHeader"
if errorlevel 1 (
reg add %regpath% /v DisableServerHeader /t REG_DWORD /d 00000001
shutdown /r /t 0
This will add the registry entry if it does not exist and reboot the instance. This will only occur whenever the instance is re-provisioned as the registry entry will then no longer be set.
Make sure that the Build Action is set to None and the Copy to Output Directory is set to Copy always for the batch file.
Ensure that the batch file is configured as a startup task and is run with elevated privileges. Add the following xml to the ServiceDefinition.csdef file in the WebAPI.Azure project:
<Task commandLine="Configure_HTTP.SYS.cmd" executionContext="elevated" />
Deploying to Azure and trying the URL with the illegal character now results in all headers being suppressed.
With a bit of work you can suppress all the headers in your ASP.NET application running in Windows Azure.
Be mindful though, that removing these excessive headers is not a silver bullet that will magically make your web application 100% less likely to be attacked. But by adding in these additional layers you at least can exclude attackers that look at specific response headers to determine whether or not you are an interesting target.