Whenever you make use of ViewState, Session, Forms authentication, or other encrypted and/or secured values, ASP.NET uses a set of keys to do the encryption and decryption. Normally, these keys are hidden and automatically generated by ASP.NET every time your application recycles, but there are times when you want to specify a particular, persistent key. This article will explain why hard-coded machineKeys are good, and how to generate random ones for ASP.NET 1.1 or 2.0.
Why you Want a Persistent Key
There are two keys that ASP.NET uses to encrypt, decrypt, and validate data in ViewState, Forms Authetication tickets, and out-of-process Session data. The
decryptionKey is used for encryption and decryption of authentication tickets and encrypted ViewState information. The
validationKey is used to validate ViewState and ensure it hasn't been tampered with, and generate unique application-specific session IDs for out-of-process session storage.
You can run into problems if the key changes between postbacks, e.g., if the keys used to generate the ViewState information are different from one page to the next. If that happens, the ViewState validation will fail (because the
validationKey after postback will be different from what was used pre-postback) and the user will get an Invalid_ViewState error. Different keys across postback can also mean that your Forms Authentication tickets will fail, requiring users to log back into your application; out-of-process session information will be lost (since the session IDs will change); and encrypted ViewState information will be unable to be decrypted and read.
Lastly, if you want to use encrypted passwords with ASP.NET 2.0's Membership provider, you have to provide a static key, or else you'll get a You must specify a non-autogenerated machine key to store passwords in the encrypted format error.
Why Would the Key Change?
Keys can change across postbacks more often than you'd expect. One way is if you're running a web farm. By default, the
validationKey used to create the MAC is randomly generated by ASP.NET when the application pool starts up. This ensures that the validation key is unique and changes periodically. However, since the key is different from server to server, if you're viewing a page on Server A and post it to Server B, when Server B generates a MAC based on the viewstate data, that value won't match the MAC value when the page was initially served by Server A. Thus, you'll get an Invalid_Viewstate error.
Another reason the
validationKey and decryptionKey (and thus the MAC) will be different is if you cross application pools. If you view a page running in pool A, and post to another page on pool B (e.g., through
Server.Transfer), the keys will be different & you'll get a mismatch.
decryptionKey can change mid-session for users if the application pool restarts. Assume some user is viewing a page on your site and filling out a form. While they're doing that, some sysadmin restarts the pool, thus generating a new key. When the user posts the page, they'll get an Invalid_Viewstate error. The application can also restart if it is set to shut down while idle (the default is to shut down pools that have been idle for 20 minutes). Imagine a user who views a page on your site, goes away for 10 minutes, then maybe spends 20 minutes filling in the form on the page. Meanwhile, no one else is on your site, so the application pool times out & shuts down. When the user finally posts the form (30 minutes after viewing it), the application pool will start back up, create a new validation key, generate a new MAC, notice that the MAC values don't match, and reward your user's diligence with an Invalid_Viewstate error.
Where to Put the Key
So if you want to create a static set of keys, you'll need to put it in the
machineKey block in either the machine.config or web.config. You can read more about the machineKey element on MSDN.
validationKeys are a maximum of 64 bytes long. In ASP.NET 1.1, the encryption algorithm was 3DES along with a maximum 24 byte
decryptionKey. ASP.NET 2.0 provided an attribute called
decryption allowing the user to specify the hashing algorithm used for decrypting data. The AES algorithm is the best choice, and accommodates a 32 byte
Please note that the below examples contain [...] to indicate that some characters were removed for readability. The actual values of the keys are long, unbroken hex-encoded strings. Don't copy & paste the below examples verbatim into your web.config -- instead, download and run the sample project, or generate random keys via the online demo.
ASP.NET 1.1 version:
ASP.NET 2.0 version:
Generating Random Keys
Now that we've discussed the keys in the
machineKey section, let's take a quick peek at some code to randomly generate keys. It's pretty simple.
The below function accepts a number of bytes, uses the .NET Crypto library to generate a byte array of random numbers, and
StringBuilder to build and return a hex-encoded string. Since the random numbers are hex-encoded, a 24 byte random key will produce a 48 character hex-encoded string.
public string getRandomKey(int bytelength)
byte buff = new byte<bytelength>;
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
StringBuilder sb = new StringBuilder(bytelength * 2);
for (int i = 0; i < buff.Length; i++)
Now we have two simple functions that use the
getRandomKey function to build and return a complete
machineKey section that can be pasted into a web.config.
public string getASPNET20machinekey()
StringBuilder aspnet20machinekey = new StringBuilder();
string key64byte = getRandomKey(64);
string key32byte = getRandomKey(32);
aspnet20machinekey.Append("validationKey=\"" + key64byte + "\"\n");
aspnet20machinekey.Append("decryptionKey=\"" + key32byte + "\"\n");
public string getASPNET11machinekey()
StringBuilder aspnet11machinekey = new StringBuilder();
string key64byte = getRandomKey(64);
string key24byte = getRandomKey(24);
aspnet11machinekey.Append("validationKey=\"" + key64byte + "\"\n");
aspnet11machinekey.Append("decryptionKey=\"" + key24byte + "\"\n");
Now all we have to do is call the
getASPNET20machinekey functions to get back a random
machineKey section for the environment of our choice.
The Sample Application
The sample application is an ASP.NET 1.1 Web Project that contains a machineKey.aspx file demonstrating the above functionality. You can also see a live demo here if you want to generate keys yourself or just see how it works.
We've discussed the
validationKey, reviewed how they can change and what problems that can cause, and discussed how to generate and deploy static keys to avoid problems. Hopefully that will help you next time you run into ViewState or other related problems.
You can read more about
machineKey and its impact at: