Question

The Environment

Okay, so I'm trying not to create a duplicate here, but I realize that this question has been sort of addressed before.

I've been doing a bunch of reading on the error:

Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

I started getting the error after we upgraded our network monitoring software and SQL version.

The page is an ASP.NET 4.0 web form external to the site it's being displayed on, written in C# with a bit of JavaScript and a fair bit of SQL. It also heavily uses .NET's chart forms (As in six chart areas on the chart, each with multiple series dynamically generated via SQL). We went from a free version of SQL Server 2008R2 to a trial of the full SQL Server 2012 instance and updated our SolarWinds Orion version to NPM 10.6.

The code is a large charting program which tracks the health of a variety of statistics averaged across each of our networks. The problem is, they asked for 'scrolling charts' which means auto-updating. I'm using a form refresh instead of a meta or full postback because there are a wide variety of variables which allow the charts to stay on a specific statistic, network, page, and time window so that when the user leaves it alone, it will refresh and keep the view they were originally looking at. If it's not more than 5 minutes ago, it will keep updating. All those values are being stored in the ViewState. (Originally, it was even worse, being stored in hidden literals on the page).

Updating the software didn't magically turn this into a web farm or cluster and we don't have a virtual environment, though we may soon.

The Research

I understand the problem is caused by the ViewState refreshing at an inconvenient time and causing the validation of the key to fail because the page loads out of sync with the validation algorithm. I've seen a lot of similar questions and answers like these:

ASP.NET Validation of viewstate MAC failed

Validation of viewstate MAC failed when on page for 20+ minutes

ScriptResource error: am I being hacked?

http://aspadvice.com/blogs/joteke/archive/2006/02/02/15011.aspx

Admittedly, this isn't customer facing, but per Microsoft:

This attribute should never be set to false in a production Web site, even if the >application or page does not use view state. The view state MAC helps ensure the security >of other ASP.NET functions in addition to view state.

My Question:

All of these answers seem to have the same solution and I'm not convinced that those are good solutions. What alternatives do I have? My superior and I don't think setting the key is good from a security standpoint. I'm willing to tweak the code to store things a different way. I've had to use session state elsewhere, but I'm still new to it. Would that run into a similar problem with refreshing before some sort of validation takes place? Can I force the refresh to run more slowly? I've also seen something about altering where the key validation happens. How is that solution from a security standpoint?

Was it helpful?

Solution

First off, I was finally able to track down my error. It turned out that I was actually managing to create a SQL Server deadlock which in turn meant that my .Net charts were throwing an un-handled NullReference Exception (derp).

All right, so, there are only a few alternatives to ViewState in ASP.NET. I finally got my page working, so I'm leaving this here for anyone who randomly happens across it.

One of the alternatives you see here on SO is to just set the machine key and enable the MAC State like so:

<pages enableViewStateMac="true">

and then:

<machineKey 
  validationKey="[128 Hex Number]"
  decryptionKey="[64 Hex Number" 
  validation="SHA1" 
  decryption="AES" />

I was moderately concerned about this for security reasons, but I couldn't make any other solution work. The conclusion I eventually came to was that I would just statically set it and re-generate the machine keys on a regular based on Microsoft's example code:

    static void Main(string[] argv)
    {
        //128 Hex characters for the validation key, 64 for the AES decryption key
        int hexLengthForEncryption = 128;

        string validationKey = Generate_New_Key(hexLengthForEncryption, argv);

        hexLengthForEncryption = 64;

        string decryptionKey = Generate_New_Key(hexLengthForEncryption, argv);

        string[] originalKeys = new string[2] {validationKey, decryptionKey};

        Generate_File(originalKeys);

        Console.WriteLine("The file has been generated. Would you like to generate new keys in a new file?");

        string yorn = Console.ReadLine();

        while ((yorn != "N") && (yorn != "n") && (yorn != "no") && (yorn != "No"))
        {               
            hexLengthForEncryption = 128;
            validationKey = Generate_New_Key(hexLengthForEncryption, argv);
            hexLengthForEncryption = 64;
            decryptionKey = Generate_New_Key(hexLengthForEncryption, argv);

            string[] freshLines = new string[2]{validationKey, decryptionKey};

            Generate_File(freshLines);

            Console.WriteLine("The file has been generated. Would you like to generate new keys to a new file?");

            yorn = Console.ReadLine();
        }
    }

This didn't totally solve my problem, though. What I ended up doing was, for the charts which have a lookup page, I added a try catch to my larger SQL queries and, despite reservations from posts like this and similar concerns with WITH(NOLOCK) on Stack Overflow, we decided that the possible pitfalls fell within acceptable error margin parameters.

In the page which actually cares about the Session ID, I had to force the program to halt briefly and return to the lookup page. Interestingly enough, it didn't crash at all with me logged out and the charts refreshing every two minutes over night. The page that doesn't use the Session ID still has a throw-away variable set like this on the main page:

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        ViewStateUserKey = Session.SessionID;
    }

And this in the control for the solution to work properly:

        //This variable is necessary to having a session state persist across postbacks, but is otherwise useless
        Session["Throwaway"] = DateTime.Now;

The Catch on this page simply redirects back to itself. The one with a search page caused a reference loop problem as the session state (which the page relied on to generate the charts) was empty and therefore broke the charts. I don't know that this will help anyone, but both the charts which use session state and those which don't require it are finally working after a network upgrade. Cheers!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top