Tuesday, September 9, 2008

How They Danced Around Your Validators

How'd This Data Get In Here?

I see this a lot while doing code reviews and cleaning up older ASP.NET web applications. Often developers will throw down some validator but not include a server side validation function, or simply not call Page.IsValid server side! Consider the following form:

<%@ Page Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <label for="<%= firstName.ClientID %>">First Name</label>
        <asp:TextBox ID="firstName" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator ID="firstNameValidator" runat="server" ControlToValidate="firstName" Display="dynamic" ErrorMessage="*"></asp:RequiredFieldValidator>

        <br />
        <asp:Button ID="submit" runat="server" Text="Submit" OnClick="Submit_Click" CausesValidation="true" />
    </div>
    </form>
</body>
</html>

There's really only two things going on here.

  • A required field validator is validating a text box client side (read: javascript) so that the user knows the text box is a required field.
  • A button is posting back the form to a server side event handler Submit_Click (below).
protected void Submit_Click(object sender, EventArgs e)

    //do something clever...
}

What I'm really trying to say is that there's a world of difference between the above and below:

protected void Submit_Click(object sender, EventArgs e)
{
    if (Page.IsValid)
    {
        //do something clever...
    }
}

Remember that Page.IsValid will tell you if ANY of the validators have controls that contain invalid data. What's even better is that the page will reevaluate these validators server side during the Page Lifecycle. Early in the lifecycle, the page walks all the validators (kept in Page.Validators) and asks them if they're valid. All you have to do to take advantage of this wonderful server side checking is call Page.IsValid before you assume your input is good.

Custom Validators

The only caveat to the above rule is that if you're implementing custom validators that do some validating with a custom javascript function on the client side then you also need to reimplement that logic on the sever side. For instance:

<asp:CustomValidator id="customValidator" runat="server" ControlToValidate="firstName" ClientValidationFunction="jsValidationFunction" OnServerValidate="serverValidationFunction">
</asp:CustomValidator>

The above requires that you not only write a client side validation function like below:

function jsValidationFunction(source, args)
{
    //Some bunch of logic
    args.IsValid = true;
}

But that you also write a server side validation function that repeats the same logic (except in C# [or whatever your code behind language is]).

protected void serverValidateFunction(object source, ServerValidateEventArgs args)
{
    //Some bunch of logic.
    args.IsValid = true;
}

Now ASP.NET knows to call your server side function and when you call Page.IsValid you'll be savvy as to whether or not the page's inputs are valid. That is, Page.IsValid will include the output of your custom server side validation function.

Is This Actually Important?

As a UI developer, a good portion of the work is validating input from the user. On the browser level this is often done in javascript, but javascript is pretty unreliable.

Even though it's currently 2008 a lot of users still browse around the web with javascript turned off (especially if they want to dodge your pesky validators). Even if they wanted to leave javascript turned on they could still use a tool like Tamper Data (FireFox extension) to simply alter the request in flight. In fact doing this is dead simple.

Want to dodge a client side validator?

  1. Download FireFox and Tamper data.
  2. Visit a web site that has form validation.
  3. Click Tools -> Tamper Data. Then click Start Tamper in the top left.
  4. Fill out and submit the form.
  5. When Tamper Data asks you if you want to tamper, do so and change the request values to anything you want. At this point there's nothing javascript can do to stop you from sending bogus values to the page.

Tools like tamper data can make it easy for any client to dodge your javascript validation.Hopefully this reinforces how important it is to validate server side! Don't trust your documents people are going to tamper with them!

For a complete break down on ASP.NET validators and what they can do check out this great Code Project article written by Paul Riley.

Best,
Tyler Holmes

No comments: