A subtle and dangerous bug appears regularly in newsgroup postings, and some have even sighted the problem in sample code from articles and books.
Take the following ASPX snippet:
<asp:textbox id="txtPassword" runat="server"/> <asp:button id="btnSubmit" runat="server" Text="Submit"/> <asp:requiredfieldvalidator id="valReqPassword" runat="server" ErrorMessage="Password required" ControlToValidate="txtPassword"/>
And the following code-behind logic:
private void btnSubmit_Click(object sender, System.EventArgs e) { SetUserPassword(txtPassword.Text); Response.Write("Password set!"); }
If you enter a blank password and click submit on this form (in a DHTML capable browser), the validation control prevents the post back and displays an error message next to the TextBox control. Testing complete, validation works, continue to the next form.
I’m sure many of you have spotted the problem, but judging from newsgroup postings this isn’t so easy for newcomers to catch. One can expose the bug by setting the EnableClientScript property of the validation control to false. Now if the user enters a blank password and clicks submit the validation error message still appears, but in addition all of the code inside the click event handler executes. Unless there is a database constraint in place, chances are the user just set their password to an empty string.
Even with client side scripting enabled, we know it would be easy to give the software un-validated input with the System.Net.WebRequest class. Client side validation works so well in the browser, however, so it is hard to see this vulnerability.
The crux of the misunderstanding is how the client side validation behavior is entirely different from server side behavior. On the client side, if validation fails, the flow of execution effectively stops. On the server side, you have to check Page.IsValid and alter the flow yourself.
Darren Neimke posted today about the difficulty in achieving elegance when writing functionality spanning client and server sides. I agree, at times it still seems much harder than it should be to get things right (with pretty code), particularly since the two sides behave so differently. Perhaps failed validation should trigger an exception on the server side - but I realize this would break many existing applications. Still, something to think about ... and watch for Page.IsValid in code reviews.