Sunday, October 28, 2012

Programmatically remove HTTP response headers

By default, all the responses of your server will be sent with some embarrassing details...

For an ASP.NET MVC web application, you have these headers :

  • Server: which is added by IIS.
  • X-AspNet-Version: which is added at the time of Flush in HttpResponse.
  • X-AspNetMvc-Version:which is  added by MvcHandler in System.Web.dll.
  • X-Powered-By: which is added by IIS.

Hackers will be happy to know the exact version of the used Framework: if your server has not been updated for a while and a major security vulnerability was found for the version of the Framework you are using, you will help them...

Moreover, these headers add a weight to all your responses (a few bytes, but I like optimizing...)

If you want to remove these headers, here are the steps to follow:

1) Removing the Server header: go to Global.asax.cs, add the Application_PreSendRequestHeaders event with this code:

   1:  protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
   2:  {
   3:      var app = sender as HttpApplication;
   4:      if (app == null || !app.Request.IsLocal || app.Context == null)
   5:          return;
   6:      var headers = app.Context.Response.Headers;
   7:      headers.Remove("Server");
   8:  }

2) Removing the X-AspNetMvc-Version header: go to Global.asax.cs, modify the Application_Start event with this code:

   1:  protected void Application_Start()
   2:  {
   3:      ...
   4:      MvcHandler.DisableMvcResponseHeader = true;
   5:      ...
   6:  }

3) Removing the X-AspNet-Version header: edit the web.config and add this element in the system.web section:

   1:  <system.web>
   2:      ...
   3:      <httpRuntime enableVersionHeader="false" />
   4:      ...
   5:  </system.web>

4) Removing the X-Powered-By header: edit the web.config and add this code in the system.webServer:

   1:  <system.webServer>
   2:      ...
   3:      <httpProtocol>
   4:          <customHeaders>
   5:              <remove name="X-Powered-By" />
   6:          </customHeaders>
   7:      </httpProtocol>
   8:      ...
   9:  </system.webServer>

The work is done, the responses of your server will be lighter and will not give important information about its versions.

Saturday, October 27, 2012

Donut Caching with ASP.NET MVC 4

I'm working on a new personal project during my free time and I chose to develop it with ASP.NET MVC 4 (hosted on Azure of course...) to test the new features of this version.

In this project, I need to display "Logged in as xxxx " (if the user is logged...) in the header of the page. This is a simple scenario to implement but caching could complicate the development of my web app...

My header is in my layout and is used everywhere but I would like to place an OutputCacheAttribute on some actions (the home page, etc.). If I put the attribute on an action, all of my users will see an header with "logged in as xxxx" of the first incoming query!

The solution to this problem is named "Donut Caching": you send a cached page from the server with a "fresh" portion which is not in cache (the donut's hole).
Concretely, the server does not generate the requested page (query the DB, etc.): it just needs to take the cached version and replace a specific part.

Luckily, you do not need to develop your own custom OutputCacheAttribute because there is already a very good package (There's An App A Pack For That... thanks NuGet!): MvcDonutCaching for ASP.NET MVC 3 and later...

To install the package, you can search through NuGet or directly type the following command in the "Package Manager Console":

   1:  install-package MvcDonutCaching

The use of this package is very simple... They have created several extension methods for HtmlHelper with the usual parameters plus another boolean parameter: excludeFromParentCache. I just have to call my partial view (with the "connected has xxxx"...) like that:

   1:  ...
   3:  @Html.Action("LoginHeader", "Account", new { lang }, true)
   5:  ...

The last parameter of Html.Action is set to true: this partial view will be excluded from the parent cache (if there is a cache on the action...). (do not pay attention to new { lang }, it's a route's value)

To make it work, you must not use the OutputCacheAttribute but the DonutOutputCacheAttribute:

   1:  [DonutOutputCache(Duration = 60, VaryByParam = "lang")]
   2:  public ActionResult Index(string lang)
   3:  {
   4:      ...
   6:      return View();
   7:  }

And that's it! The first request will be cached during 60 seconds but the LoginHeader partial view will be generated every time.

(note: of course, the donut caching only works on the server side...)