Securing the ASP.NET MVC Web.config

Security is a big subject in the web world. Largely because it’s super easy to leave your site insecure and open to attack. The default ASP.NET MVC project template is pretty weak when it comes to security. It trades security for simplicity. The ASP.NET MVC Boilerplate project template, shifts that balance more in favour of security while still trying to be as simple as possible. Several insecure settings in the Web.config file have been changed and made secure by default.

This series of blog posts goes through the additions made to the default ASP.NET MVC template to build the ASP.NET MVC Boilerplate project template. You can create a new project using this template by installing the Visual Studio template extension or visit the GitHub site to view the source code.

Securing Web.config

Turn On Custom Errors

In the early stages of development, you want to see the full stack trace of your exceptions when an error occurs on a page. When it comes to releasing your site, you need to hide this sensitive information. Unbelievably, the default ASP.NET MVC template leaves this sensitive information wide open. To hide this, you need to add the customErrors section to your web.config file and turn it on.

The problem is that we still want this setting to be turned off when debugging. This is where configuration file transforms come in. This setting is off when the solution configuration is ‘Debug’ and on when it is ‘Release’. The debug attribute in the compilation section is set in the same way.

Securing Cookies

By default JavaScript from external sites can access the cookies from the default ASP.NET MVC template. They can also be sent unencrypted over the wire, because they don’t use SSL. The httpCookies section can be added to secure your cookies (This can also be done in code but the point is that we are making it secure by default. You could easily forget to turn this on in code).

By default we set requireSSL to false because we don’t know if you are going to use SSL in your site or not. If you are using SSL, you need to turn this on.

Shut ASP.NET’s Mouth

By default ASP.NET shouts about itself a lot. It sends HTTP headers with each response telling the world and dog what version of ASP.NET your site is hosted on and even what version of MVC you are using. Below is an example of the extra headers needlessly being sent with every request:

ASP.NET Response Headers

To fix this problem you need to do a few things. The first is to set the enableVersionHeader setting on the httpRuntime section to false.

Second, you need to clear the custom headers as shown below.

Troy Hunt is a great MVC security guru and definitely worth a read on this subject.

ASP.NET Session Cookie

We rename the ASP.NET session cookie from its default name of ‘ASP.NET_SessionId’ to ‘s’. Now, users of our site, no longer have any idea what web server we are using (There are still ways to find out but we are making it harder) and we save a few more bytes being sent over the wire because we have a shorter name.

Maximum URL Request Length

By default, ASP.NET MVC allows 4096 characters in the request URL. This is to reduce the effects of denial of service attacks. You can reduce this limit further by setting the maxRequestLength setting on the httpRuntime section. The template does not do this by default but does include a comment highlighting this.

Machine Keys

Machine keys are used by MVC to generate anti-forgery tokens, which you should be using with any form on your site. If your site is deployed to a server cluster, you need to generate a machine key and add it to the system.web section of your web.config file. This is to ensure that both machines in your server cluster are using the same machine key to generate anti-forgery tokens. This link tells you more about how to do this.

Securing Third Party Plugins

The popular Elmah NuGet package is included and configured for error logging out of the box. However, to properly secure it, you should change the URL pointing to it (An attacker can only probe your Elmah page for vulnerabilities if they can find it). You should also use some form of authentication to limit the Elmah page to certain roles or users. Both of these steps can only be taken by the person using the template. However, where we can’t write the code for you, we add liberal comments and add an entry into the check-list so you don’t forget to do this. By default we also allow remote access to the Elmah pages, consider turning this off if you have local access to machine the site is hosted on. Here are the relevant app settings:

Glimpse is another great tool to help with debugging and diagnostics for your site. Like Elmah, Glimpse has it’s own URL which you should rename. Glimpse is turned off in ‘Release’ mode for security reasons but you could keep it turned on and use authentication to limit who can access it. The relevant section for Glimpse is shown below.

Securing Anti-Forgery Tokens

I’m not quite sure why but configuring the ASP.NET MVC anti-forgery tokens cannot be done in the web.config file. The following code can be found in the Global.asax.cs file.

We are renaming the anti-forgery cookie from ‘__RequestVerificationToken’ to ‘f’. This saves a few bytes and obscures the technology we are using a little. You can also require SSL for the anti-forgery cookie to be sent over the wire. This is commented out by default but if you are using SSL, set this to true for added security.

(UPDATE) Removing Tracing

Enabling tracing while debugging your site is a fairly common occurrence. It can be done with a single line of config:

Your tracing information can be easily views by navigating to http://YourSite/trace.axd as shown here:

ASP.NET Tracing Trace.axd Page

The security angle on tracing is two-fold. First is the most obvious, you could leave the trace.axd page open to anyone who knows to try that URL on your site. Thus, leaking valuable inside information about your site, as well as the version of ASP.NET and .NET you are using. The fix for this is simple, you just need to remember to remove the tracing node from your web.config file.

Once again, you can use configuration file transforms to fix this problem. In your Web.Release.config file, you can add the following code to remove tracing but only when the site is built in release mode:

The second problem is that even if you do this, accessing http://YourSite/trace.axd causes a 500 Internal Server Error on your site! This gives an attacker a clue that you are using ASP.NET. The correct thing to do is for the site to respond with a 404 Not Found error page instead. It turns out that in release mode you have to remove the tracing HTTP handlers altogether to stop your site responding to this URL. You can do that by adding the following snippet to the Web.Release.config file:

(UPDATE) 403.14 Forbidden Responses to Directories

Navigating to a directory using IIS and ASP.NET MVC can cause a 403 Forbidden response to be returned. Actually, its a 403.14 Forbidden response to be exact. IIS is basically telling us that directory browsing is disabled (As it should be, directory browsing is a severe security risk. It can allow attackers to see your Web.config file with all your connection strings in it!). You can see what happens when I navigate to the physical ‘/Content’ folder below:
403.14 Forbidden Response
So what is the problem? Well, a user would expect a 404 Not Found response if a resource is not found. A 403.14 Forbidden response tells a potential attacker that there is a folder there and that you are using IIS. Not the most useful information to an attacker but combine it with other information and it could be useful. The way to fix this is to handle 403.14 errors and replace the response with a standard 404 Not Found. We just need to add the code below:

Just adding this is not enough however. If I fire up Fiddler Navigating to the ‘/Content’ folder of the site now results in a 301 Document Moved response, followed by a 404 Not Found. We can do much better than that.
Fiddler 301 Courtesy Redirect
To get around the above issue, you need to turn off default document handling in IIS. Please do note, that this will stop IIS from returning the default document (Using whats called a courtesy redirect) when navigating to a folder e.g. navigating to ‘/Folder’ which contains an index.html file will not return ‘/Folder/index.html’. This should not be a problem as we are using ASP.NET MVC controllers and actions and not physical files.

Now, navigating to ‘/Content’ will return us a simple and correct 404 Not Found and we don’t have the courtesy redirect any-more too. Take a look at the same request in Fiddler:
Fiddler 404 Not Found

Conclusions

IIS seems to have a lot of strange behaviours that have a detrimental effect on security. If you use the above settings however, you can cut out IIS’s extra features that you don’t need or want. Look out for the next post when I’ll be discussing the very cool NWebSec NuGet package, which provides a whole host of comprehensive ASP.NET MVC security related filters which you can apply to your site.