ASP.Net Value Shadowing

Posted by on June 7, 2011

Value shadowing occurs when the developer does not specify the specific collection to pull a value from when multiple collections exist in the same context.  The Request object is a great example of this.  The Request object contains Querystring, Form, Cookies, and ServerVariable collections.  Normally, if a developer wanted to access a value from a form variable, they would use something similiar to the following code snippet:

  1: string str = Request.Form["myValue"].ToString();

The above code snippet accesses a specific collection within the Request object.  They could also access that value using the below two lines of code:

  1: string str = Request["myValue"].ToString();
  2: string str2 = Request.Params["myValue"].ToString();

The above code snippet is susceptible to value shadowing because it does not specify the specific collection.  ASP.Net will loop through each collection until it finds the key name specified and take the first value.  The loop starts with the QueryString collection, then goes to Forms, Cookies and finally Server Variables.

UPDATE:  ASP.Net Server Controls do not use the Request.Params collection as previously stated.  The framework determines if it is a POST or a GET and passes the correct collection to be parsed.  However, the following information still stands true.

It doesn’t matter if the form is set to GET or POST, it will still be able to populate the control properly.  This feature is great for ease of use and having some nice generic code, but what about security?  Lets look at how this can cause a security problem if not properly handled.

Cross Site Request Forgery (CSRF)

This article assumes you already understand what CSRF is and how it works.  If you don’t, do a quick Google search and it will clear it up.  CSRF can be done using POST or GET, but GET is much easier to implement.  By default, ASP.Net forms and other functionality work via the POST method.  If we could submit a GET instead of a POST it would open up the attack surface a great deal. No longer do we need someone to visit a page with a form on it, but we could actually embed the GET request (a link) in emails or other medium.

Fortunately for the attacker, unfortunately for the developer, .Net uses Value Shadowing for its controls.  This means all server side controls, ie. Viewstate, EventValidation, EventCommand, EventArguments, etc..  It is possible to take the values that would be submitted as part of the form and just add them to the Querystring instead.  Now there is a GET request that is comparable to the POST request.  ASP.Net Webforms does not check whether a post back comes from GET or POST.  The one thing to keep in mind is that the URL in a GET is limited in size.  If the form is large and the viewstate is very large, this could block this technique from working.  This depends on the way the application is configured (more later).

Login Via GET

When working with a login page, it is important that you protect the user and their credentials.  There are many reasons why this is important, for example, compliance, privacy, etc..  Logins should be done only via a POST request.  One reason for this is because a GET request is logged in log files (IIS).  Even if the url was https, a login via GET would log the username and password in the logs.  This is a big no-no.  As I have just shown, it is possible to login via GET if you wanted to in most ASP.Net webform applications.  Most developers will not check to actually see if the request is a POST and enforce it.  If the dev did enforce this, you could still submit the values, but it would be worthless unless you could gain something from it.

One way the developer could block logging in via the GET is by checking the HTTPMethod of the Request object like this:

  1: if (Request.HttpMethod == "POST")
  2: {
  3:    //Do Login
  4: }

What It Means

The two above scenarios show the base techniques to create other attacks.  The key is that the Page.IsPostBack property doesn’t look to see if the form is a POST, it is looking that specific variables are present in the Request (ie. Viewstate, EventValidation, EventArguments, etc).  It is important for developers to understand this so they can properly protect against it.

Protection Mechanisms

There are a few different ways to help protect against these issues.

One way is to check the HttpMethod as in the previous code sample.

Another way is to actually check to make sure the values come in the collection you expect them to.  If you expect POST variables, make sure they exist in that collection.

MAKE SURE EventValidation is enabled.  This is important because when EventValidation is enabled, it will validate the ViewState data.  If EventValidation is disabled then you can cause a valid Postback by just sending an empty __ViewState value in your querystring.  ViewState can be very large so by requiring it, it can block using the querystring because of its length.

MAKE SURE you use the ViewStateMAC.  This helps stop the ViewState from being tampered with.

MAKE SURE you set the ViewStateUserKey to a user unique value.  This is VERY IMPORTANT!.  When this is properly set, most of the above methods to attack will not be successful.  Lets take just a moment to talk about this.

When you use the ViewStateUserKey, it adds a special value to each user’s ViewState.  To perform CSRF, the attacker needs to preset the attack vectors with values they have obtained.  When they create the page, the ViewState they submit (which should be required if you are enabling EventValidation) would be different than the ViewState you would get.  This would block this attack from working.  In the case of the Login Via Get, the ViewState would change for each session (roughly each time you log in) and would decrease the reasons for doing this.


The benefits of how ASP.Net handles these collections to create their objects are huge.  However, they must be handled with caution.  Make sure you are properly following Security Best Practices and you are testing your functionality to make sure it is secure.  I do not try to cover every possible example or attack vector.  Instead, I try to get the idea across so developers can have a better understanding and produce more secure code.


Comments are closed.