DotNetNuke: Workaround for “Validation of viewstate MAC failed” exception when using the DNN 7 login form in multiple tabs

As I’ve written in one of my previous posts, I found out that one gets a “Validation of viewstate MAC failed” exception when submitting a DNN login form and the login status has changed from “not logged in” to “logged in” after the login form initially was loaded (e.g. by using an addition browser tab to log in).
After contacting the DNN support team it turned out, that this is not a bug, but a security feature in DNN. In detail, DNN adds the username of the current session to the APS.NET ViewStateUserKey (see “Take Advantage of ASP.NET Built-in Features to Fend Off Web Attacks” on MSDN for more information).
In DNN profession knowledge base, two resolutions are described which both have their drawbacks:

  • One could edit the Default.aspx.cs and remove the username from the ViewStateUserKey which has to be done after each DNN update because Default.aspx.cs will be overwritten when updating the framework.
  • One could disable “ViewState MAC validation” entirely by setting enableViewStateMac to false in Web.config file which is not recommended due to security problems.

I finally came up with the following code snippet that I’ve added to the code behind file of the skin:

protected override void OnInit(EventArgs e)
  // Catch "Validation of viewstate MAC failed" exceptions and redirect the user 
  // to the current page (i.e. force a redirect on the client)
  Page.Error += (sender, args) =>
    if (!(HttpContext.Current.Error is HttpException)) return;
    if (!(HttpContext.Current.Error.InnerException is ViewStateException)) return;
    Response.Redirect(Request.UrlReferrer == null ? Request.Url.ToString() : Request.UrlReferrer.ToString());

In detail the code above adds an error handler that catches “Validation of viewstate MAC failed” exceptions and forces the client to reload the current page in case of such an excpetion (which updates the ViewStateUserKey according to the current session state). Since this error handler needs to be added on every page, the skin is the perfect place to put the code into.