ViewStateUserKey Doesn’t Prevent Cross-Site Request Forgery

ViewStateUserKey is not a completely effective mitigation against Cross-Site Request Forgery. It doesn't work for non post-backs (I.e. GET requests), and it doesn't work if the ViewState MAC is turned off.

In several different places, we see a piece of advice repeated - use the ViewStateUserKey property to prevent One-Click Attacks. Often, this piece of advice is accompanied by the following code:

void Page_Init(object sender, EventArgs e)

{

ViewStateUserKey = Session.SessionID;

}

What exactly does this code do? To understand it, we first need to look at the ViewState mechanism itself. The ViewState is an ASP.NET mechanism used to persist the value of web controls between post-backs. This allows a lot of the drag and drop, UI-driven ASP.NET architecture to function "auto-magically" by serializing and de-serializing data automatically on the fly.

The ViewState is encoded and stored as a hidden field. This introduces security issues, because the value is under the control of the client. There may be a value stored in a field that you do not want someone to see and modify, like an admin-only control with the visible property set to false.

ASP.NET helps us out by introducing two mechanisms to help protect the ViewState. ViewState MAC prevents tampering with the ViewState by introducing a separate Message Authentication Code that is verified when the ViewState is submitted. ViewState Encryption protects the ViewState confidentially by encrypting the ViewState value. By default, the ViewState MAC is enabled, and ViewState Encryption is not.

The ViewStateUserKey property is an optional addition to the data used in ViewState MAC calculation. If that value changes between post-backs, the ViewState MAC calculation will fail and the page will cause an error.

When we set the value of ViewStateUserKey to something associated with a particular user (like a Session ID or a Username), we are making sure that the ViewState is valid only for that user.

Back to One-Click Attacks. One-Click Attack is sometimes incorrectly referred to as Microsoft's name for Cross-Site Request Forgery. However, this is not entirely correct.

One-Click Attacks refer to CSRF attacks that use a malicious ViewState to perform the request. Because web forms developed with ASP.NET use ViewState for post-backs, the attacker can perform the post-back they want the user to perform unknowingly, and record the ViewState. Due to the way that ASP.NET ignores HTTP verbs when using Request.Params versus Request.Form, and in web controls, this request can often be made via GET.

Example:

http://site/Default.aspx?__VIEWSTATE=%2FwEPDwULLTExOTcyMDExODNkZAShpi32DKvqCd4uvHuQ%2FmmnBcdY&TextBox1=<MALICIOUS_CONTROL_DATA_GOES_HERE>&Button1=Button&__EVENTVALIDATION=%2FwEWAwKEyYGZBwLs0bLrBgKM54rG3sCHijug9ibUUfHX808cCvcppg1i

This link can be used in a CSRF attack. It is then known as a one-click attack, because it uses the ViewState. This, however, is not:

http://site/DeleteUser.aspx?user_id=123456789

If the page is not a post-back (as in the case of a direct link), the ViewState MAC is never checked. Several ASP.NET applications allow you to modify data without submitting a form. Consider ASP.NET MVC - it doesn't even use post-backs.

Furthermore, the ViewState MAC can be disabled at the page level:

<%@ Page Language="C#" EnableViewStateMac="false"%>

or in web.config.:

<pages enableViewStateMac="false">

</pages>

ViewState MAC is often disabled for (perceived) performance reason, or (more likely) if there is some functionality in the application that causes the ViewState MAC to cause error.

This reminds of problems with Request Validation is ASP.NET - the mechanism works, sometimes. This can be dangerous, because people rely on it and can get burned. The solution is to write something similar to CSRFGuard from OWASP in .NET. I have a feeling that the newly resurgent OWASP .NET project will add this to their to-do list.

Published Thursday, May 29, 2008 2:30 PM by Alex

Comments

# Giving the OWASP .NET ESAPI a Second Look@ Tuesday, September 09, 2008 6:20 PM

I've started up work again on the OWASP .NET ESAPI . Since a few months ago, when I translated the OWASP

# Checking for ViewStateUserKey using FxCop@ Thursday, September 25, 2008 3:43 PM

ASP.NET has had a mitigation to prevent against CSRF/One-Click attacks since 1.1 with the use of Page.ViewStateUserKey

# Preventing CSRF, the Right Way@ Friday, October 17, 2008 3:01 PM

CSRF ( Cross-Site Request Forgery ) attacks occur when an attacker forces a victim to perform an action

# Announcing AntiCSRF for ASP.NET@ Saturday, December 13, 2008 5:47 PM

Announcing AntiCSRF for ASP.NET

# Checking for ViewStateUserKey using FxCop@ Thursday, January 15, 2009 11:12 AM

ASP.NET has had a mitigation to prevent against CSRF/One-Click attacks since 1.1 with the use of Page.ViewStateUserKey

# re: ViewStateUserKey Doesn’t Prevent Cross-Site Request Forgery@ Monday, February 09, 2009 8:20 AM

Good article, you clarified a subtle difference between one-click attack and csrf.

However, I do not quite agree on the following:

"This, however, is not:

site/DeleteUser.aspx

If the page is not a post-back (as in the case of a direct link), the ViewState MAC is never checked. Several ASP.NET applications allow you to modify data without submitting a form.

"

1. Allowing "delete a user with a httpGet" is a design error.

2. Based on 1, when people are talking about CSRF, they are refering to CSRF using a post, and so ViewStateUserKey do protect again this type CSRF. We do not need to worry about the CSRF for a httpget endpoint, since it's a design error, well-informed people simply dont design web that way.

by Xie

# re: ViewStateUserKey Doesn’t Prevent Cross-Site Request Forgery@ Friday, February 20, 2009 10:32 AM

KeepItLocked, if the ViewState MAC is not checked for a GET request, what are the true implications to CSRF? I believe a valid ViewState is still required. If so, how would an attacker be able to know the correct value for his CSRF attack with the user-specific data in there?

by Dave Ferguson

# re: ViewStateUserKey Doesn’t Prevent Cross-Site Request Forgery@ Tuesday, February 24, 2009 11:52 AM

A couple people asked about how GET requests can be problematic.

Xie - I disagree that problems where HTTP GET requests cause side effects should be ignored. For instance, ASP.NET doesn't care if you use GET or POST for postbacks, as long as you submit a valid ViewState. Check out Arshan and Jeff's paper about this (www.aspectsecurity.com/.../Bypassing_VBAAC_with_HTTP_Verb_Tampering.pdf)  Too many web sites and frameworks are verb agnostic too simply ignore cases where POST isn't used.

Dave - If a website doesn't use Web Controls or check the IsPostBack property, but simply performs some business function based on the request parameters in the PageLoad method, then the ViewState is never used. I've seen pages like this where people set up a link that performs some action, rather than a form postback via web controls. While it's probably not common, it have seen this several times in the wild.

by Alex