CascadingDropDownList and Page Validation

While working with the AJAX Control Toolkit (http://ajax.asp.net), I came across something interesting with the CascadingDropDownList control and ASP.NET page validation.

What Does the CascadingDropDownList Do?

The control is used to create tiered drop-down lists that each depend upon parent values for their own data population.  The canonical example given regards using three DropDownList controls to narrow a selection of a car.  The first list displays a list of manufacturers, the second a list of models, and the final a list of common packages, with each successive list control populating only the relevant values based upon its parent.  For example, selecting “Ford” from the manufacturer list would populate “Focus, Sierra, Probe, F-Series, etc…” in the model list.  Selecting “F-Series” would populate “F150, F250, F350, etc…” in the package list.

What’s the Problem?

When the CascadingDropDownList control renders the child lists, it makes an AJAX server request to a web service supplying the selected parent value and requesting the list of relevant child values.  It then uses client-side script to populate the child DropDownList control with the list of returned values. This means that the contents of the child drop-down lists are being modified on the fly by JavaScript and the final values in the list will not match the list that the ASP.NET page thinks it rendered.  The ASP.NET security model contains validation upon a postback to ensure that the contents of a drop-down list being posted back match those that were rendered to avoid injection attacks (see the section below on injection attacks if you want a refresher).

When the page posts back, an exception is raised by the ASP.NET framework because the contents of the originally rendered list don’t match the newly populated list.  ASP.NET provides a solution to “permit” a control to be modified on the fly, however it requires a call to ClientScriptManager.RegisterForEventValidation for each of the additional valid values that might appear.  Since we don’t know (server-side) ahead of time which option the user will choose client-side, we can’t know the list of options that the JavaScript control will add, thus preventing us from using that solution.

The Atlas Solution

The only official solution provided by the Atlas team is to disable validation for the page:

http://ajax.asp.net/ajaxtoolkit/Walkthrough/CCDWithDB.aspx

However, even that team admits that this must be done with extreme caution and a complete understanding of the consequences.  It is fine to disable the automatic validation for a page as long as you are validating the received values manually or if you really trust the users of the application not to inject.  (hint: even on intranet apps you never trust the users not to inject because automated bots and viruses running on client machines inside the intranet are becoming advanced enough to post injections to page controls without the user’s knowledge, not to mention the “password on a sticky note on the monitor” hole.)

Why is the Solution a Problem?

The solution can be worked.  Server-side validation of incoming data from input controls (including DropDownList controls) is a good practice to begin with.  However, it raises some interesting limitations with regards to the standard integration models used by most developers.  If, for example, you are using the <ObjectDataSource> control to take parameters from your page controls and feed their selected values directly into a stored procedure or SQL query, you won’t get the opportunity to manually validate the input.  This means that a control on the page that is used as a parameter in the ObjectDataSource could have an injection string posted back as its value and sent directly to the stored procedure without the opportunity for server-side validation.  This opens up the injection hole and could only be solved by coding some pretty awkward stored procedures.  There is a better way.

Finding a Solution

Things We Know

  • I love the CascadingDropDownList control and want to still use it.
  • To avoid ASP.NET raising validation errors, page-validation must be disabled for the page.
  • Disabling automatic validation and failing to perform manual validation can open a security hole.

Compromises?

  • For the particular page using CascadingDropDownList, don’t use the ObjectDataSource directly.  Bind to the control with the three lines of code it takes in the code-behind file.  You can still use the TableAdapters and fantastic ASP.NET 2.0 DataSet pattern, you just need to validate the incoming paramters with a few assertions before running off with the input to the database.
  • As a lesser, potentially still dangerous, and (to my mind) somewhat messy solution, you could bullet-proof your stored procedures with validation – but this feels like a future stumble and could get ugly in maintenance, testing, and debugging.  Just write the manual validation code and be done!

Injection Attacks You Say?

Without page validation a security hole appears.  Consider the following scenario.  A page is rendered with three items in a drop-down list, arbitrarily the names of three authors.  The ID and name of the author are rendered as the value and text respectively.  Because this is client-side html, the contents of the list can be modified before the page is posted back.  Say you insert the following into the html for the drop-down list:

<option value=”1 or 1=1;“>Foo</option>

This adds a new item to the list whose value is ‘foo’ or 1=1;

If the stored procedure being called was:

SELECT *

FROM   Author

WHERE  AuthorID = @selectedAuthorID

then the executed SQL would now end with:

WHERE AuthorID = 1 or 1=1;

Why is that a Bad Thing?

Well, for one the stored procedure or sql query will now return every item in the table because OR 1=1 will always evaluate to true.  Secondly, there are far, far worse injections that can be performed depending upon the rights of the user that the web application uses to connect to the database.  Because most applications have a single user account for the entire web application (restricting admin features only by url or declarative security), that account usually has vastly elevated rights.  You can now inject any SQL command after the WHERE clause.  For more information on SQL injection attacks, see http://www.unixwiz.net/techtips/sql-injection.html

This entry was posted in AJAX, ASP.NET and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *