Scott on Writing

Musings on technical writing...

Don't Trust ViewState

Today I was pointed to a recent email to the BUGTRAQ mailing list (a mailing frequented by security experts) concerning replay attacks and ASP.NET view state.  The email was posted by Michal Zalewski, titled: ASP.NET __VIEWSTATE crypto validation prone to replay attacks.  As I describe in my article Understanding ASP.NET ViewState, The contents stashed in the hidden __VIEWSTATE form field are base-64 encoded and (by default) cryptographically signed to prevent view state tampering by a malicious client and ensure validity of the view state's contents across postback.

The signature occurs by salting the view state with both the HashCode for the virtual directory in which the page exists along the page's HashCode.  This signature prevents a nefarious user from modifying the view state and posting it back.  If such a situation unfolds, the ASP.NET runtime will not that the reposted view state's signature does not match up and throw an exception.  Similarly, this mechanism prevents against replay attacks where the view state is taken, without modification, and posted back to a different page.  Since the view state is signed by the page's HashCode, the signature wouldn't match up.

What Michal reasoned out, though, was that the view state was vulnerable to replay attacks to the same page.  His example is a common one: you have an eCommerce site where the data loaded on the page is dependent upon querystring parameters, such as GetProduct.aspx?ID=productID.  If things like price are stored in the view state (such as in a shopping cart DataGrid or put there programmatically), a frugal visitor could visit GetProducts.aspx?ID=cheapProduct, save the view state in the hidden form field, then repost that to GetProducts.aspx?ID=expensiveProduct.  The end effect might be that the user could order the expensive product for the price of the cheap one.  (Of course this would only be possible if the eCommerce site relied solely on the view state for pricing information when computing the final bill.)

The point is, don't trust view state (or the data that is put there by Web controls, such as the DataGrid).  That is, if you have important information, such as pricing data, it's OK if it is placed in view state (such as in a row in a DataGrid), but don't grab the pricing data to charge by just poking around the view state (as in programmatically accessing the contents of a DataGrid).  Instead, if you need to get pricing information (or any other important bit of information) for the final order processing, it is imperative that you requery the database.

Another point Michal made in his email was that view state can be used in a one-click attacks.  That is, a nefarious hacker could pass along one view state through a third-party, the end effect being that the third-party sees a page with a view state they did not “create” themselves.  Michal points out that to avoid this there needs to be someway to associate the view state with information particular to a user.  This is possible in ASP.NET 1.1 via the ViewStateUserKey property, which is an additional, optional parameter that is used as a salt in the signature.  You can assign this property to some unique user value to prevent the attack; see Improving Web Application Security: Threats and Countermeasures for more information.

The last point of Michal's email to BUGTRAQ was concerned unsigned view states.  If you opt not to sign the view state (that is, if you set EnableViewStateMac to false), ASP.NET naively attempts to decode the view state passed in.  This can be used as a denial of service vector by dumping in a very large hidden view state field, which can severely hamper the performance of the web server.  (Of course, the web server is likely configured to reject any incoming request that's larger than 4 MB in size, but this is still an easy point of attack since crafting and posting a large view state is a trivial task from the attacker's point of view.)  To protect yourself from this don't set EnableViewStateMac to false, if possible.  There have been some claims that you need to set EnableViewStateMac to false in order to have Server.Transfer work properly.  There is a workaround, as discussed in this KB article.  It is my understanding, however, that you'll need to set EnableViewStateMac to false if you are using a web farm without server affinity.

I followed up Michal's email to BUGTRAQ with an offlist discussion.  His main point, as I understand it, is that he in concerned because developers might think that view state is a safe place to put sensitive data or data that need not be revalidated due to the signing/encrypting options view state provides.  However, as Michal's email shows, view state - even signed and/or encrypted view state - is not safe from replay attacks on sites where a single page's differs merely by the querystring.  The short of it - don't trust that your view state information has not been modified and always requery the database before using information whose correctness is important.

posted on Tuesday, May 03, 2005 5:03 PM

Feedback

# Never Trust User Input: The ASP.NET ViewState case 5/4/2005 5:30 AM Hernan de Lahitte's blog

# I bookmark del giorno #4 5/5/2005 4:46 AM Lorenzo Barbieri @ UGIblogs!

# Links da semana... 5/5/2005 6:32 PM Rui Quintino

# re: Don't Trust ViewState 5/8/2005 2:03 PM GuyIncognito

How about avoiding ViewState like the plauge! ;) Of course that will be a lot easier with the introduction of "control state" (I forget the actual name) in ASP.NET 2! :)

# re: Don't Trust ViewState 5/10/2005 6:13 AM Semi-anonymous guy

Nice points on the viewstate.

For the web farm and the EnableViewStateMac flag, you can have it enabled if you manually set the validationKey and decryptionKey properties of the machineKey section in your web.config. If this matches on all servers, it will work properly.

It does introduce a weak link on your keys, since normally you don't even know what the keys are, but hopefully you don't have employees going around posting sensitive hex codes around on the net. If someone else gets access to your web.config you've got bigger issues than replay attacks.

# re: Don't Trust ViewState 5/13/2005 7:34 AM George Hicks

Good advice. For those overriding viewstate behavior (by overriding the Page methods), the viewstate vulnerability largly goes away. Still the reasons for overriding viewstate involve lots of tradeoffs.

I think it's also good to point out here that the Crypto library makes verification of data very easy. For instance, securing a query string by adding an md5 hash works quite well.

# re: Don't Trust ViewState 7/15/2005 4:59 AM nick

viewstate("something") = some crap __VIEWSTATE

viewstate(guid.newguid.tostring) = more crappy __VIEWSTATE

viewstate(viewstate(guid.newguid.tostring)) = session.sessionid = very crappy __VIEWSTATE

and some other crap algorithm, this i made sure viewstate is not hacked, at least within 10 minutes

# re: Don't Trust ViewState 4/24/2006 11:35 AM Jonathan

Control State works the same as viewstate as far as I know.. tis even stored in the same place, manner... only has some extra stuff added so that the runtiome knows it belongs to some specific control, also uisers cant disable it by disableing viewstate.
But knowing this... i would imagine both are succeptable to the same security hacks.

Title:  
Name:  
Url:
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments   

Add To Your Reader

My Links

Archives

Post Categories

 

I am a Microsoft MVP for ASP.NET.
I am an ASPInsider.
<May 2008>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Comment Stats

DayTotal% of Total
Sunday 1866.8%
Monday 37913.9%
Tuesday 45316.7%
Wednesday 50418.5%
Thursday 53519.7%
Friday 49418.2%
Saturday 1666.1%
Total 2717100.0%

Hour1Total% of Total
12:00 AM 652.4%
1:00 AM 682.5%
2:00 AM 622.3%
3:00 AM 742.7%
4:00 AM 572.1%
5:00 AM 1033.8%
6:00 AM 1084.0%
7:00 AM 1585.8%
8:00 AM 1716.3%
9:00 AM 1475.4%
10:00 AM 1716.3%
11:00 AM 1816.7%
12:00 PM 1886.9%
1:00 PM 1696.2%
2:00 PM 1605.9%
3:00 PM 1324.9%
4:00 PM 1073.9%
5:00 PM 923.4%
6:00 PM 913.3%
7:00 PM 963.5%
8:00 PM 833.1%
9:00 PM 782.9%
10:00 PM 792.9%
11:00 PM 772.8%
Total 2717100.0%

Comments by Blog Entry Date/Time

Day Entry MadeAvg.Total
Sunday 5.54144
Monday 5.22339
Tuesday 4.28419
Wednesday 7.67637
Thursday 6.90607
Friday 5.48411
Saturday 5.33160
Total 5.842717

Hour1 Entry MadeAvg.Total
12:00 AM 5.0035
1:00 AM 1.002
5:00 AM 0.000
7:00 AM 7.0035
8:00 AM 5.35107
9:00 AM 6.32278
10:00 AM 6.47246
11:00 AM 4.41181
12:00 PM 6.88330
1:00 PM 3.00111
2:00 PM 5.41222
3:00 PM 8.64285
4:00 PM 4.0589
5:00 PM 5.92154
6:00 PM 4.52113
7:00 PM 9.67174
8:00 PM 9.80147
9:00 PM 5.05111
10:00 PM 5.4265
11:00 PM 4.5732
Total 5.842717

Learn More About Comment Stats
1 - All times GMT -8...


Blog Stats

Favorite Web Sites

My Books

My MSDN Articles