|Delphi Clinic||C++Builder Gate||Training & Consultancy||Delphi Notes Weblog||Dr.Bob's Webshop|
How to handle “dangerous” HTML input in ASP.NET web forms
ASP.NET 1.1 has this nice "feature" of automatically validating the incoming Request (QueryString, Form and Cookies) to prevent script attacks.This new validation code will raise an HttpRequestValidationException, which will be raised before the OnInit itself is executed.
As an example, let’s use Delphi or any other ASP.NET supporting development environment to create a new ASP.NET application.
Place a TextBox, a Button and another TextBox control (the second one with the TextMode property set to MultiLine).
To complete the example, let’s add a single line of code to the Click event of the Button, as follows:
procedure TWebForm1.Button1_Click(sender: System.Object; e: System.EventArgs); begin TextBox2.Text := TextBox2.Text + #13#10 + TextBox1.Text; end;If we compile and run the project, the result is a nice little ASP.NET application that can be used to add single line entries from the first TextBox to the multi-line contents of the second TextBox. So far, so good, and you can add just about any text you wish.Just about, since not everything is possible.If you try to add a little decoration to the input string, for example using HTML tags like and then all of a sudden we get a not so nice message from the ASP.NET environment, telling us that HTML tags are considered potentially dangerous, and a potentially dangerous Request.Form value was detected from the client, namely
“TextBox1=”Test met bold”.
The problem I have with that, is the fact that the resulting error message is not very nice. And although I could define a custom error page, I'd much rather give the user a friendly reminder that HTML is not allowed as normal ASP.NET input. Of course, I could turn the validation off, by specifying validateRequest="false" in the Page directive of my ASP.NET page, but I don't really want to do that, since that would open up my ASP.NET page for some actual (and potentially more serious) script attacks.There’s a reason this validation exists, so we should not disable it just because it’s inconvenient.
First Attempt to Catch The Error
If you try to trace of debug this application, you will find that it’s not possible to catch an exception in your Page events, since the exception itself is raised before we can assign an event handler to the Self.Error property in the InitalizeComponents routine. In my weblog at http://www.drbob42.com/blog I describe a technique where I wanted to make sure the Error event of my ASP.NET page was assigned before the validation is raising an exception.To do this, I declared a constructor, and set the Error event manually (since the assignment in the InitializeComponents would be too late).In effect, I ended up with the following code:
constructor TWebForm1.Create; begin inherited; Include(Self.Error, Self.TWebForm1_Error) end;And then in the Error handler I cleared the error and set the StatusCode back to 200, as follows:
procedure TWebForm1.TWebForm1_Error(sender: System.Object; e: System.EventArgs); begin if (Server.GetLastError.GetBaseException is System.Web.HttpRequestValidationException) then begin Response.Clear; Response.Write('Sorry, not HTML allowed...'); Response.StatusCode := 200; Response.&End end end;
Second Way to Catch The Error
However, instead of doing it this way, we can also simply override the OnError method, and prepare to handle the error in that method. To implement the new solution (instead of the constructor and TWebForm1_Error method as described above), place your cursor inside the TWebForm1 class, press Ctrl+Space which will present you with the list of methods from the System.Web.UI.Page base class which we can override.Select the OnError method and press enter.Next, press Ctrl+C to generate the implementation for the OnError method, and implement it as follows:
procedure TWebForm1.OnError(e: EventArgs); begin inherited; if (Server.GetLastError.GetBaseException is System.Web.HttpRequestValidationException) then begin Response.Write('Sorry, not HTML allowed...'); Response.StatusCode := 200; Response.&End end end;
Nicer Way to Catch The Error
This still results in an error page (a bit nicer), and not my original page.So, I had to add a little trick to it, redirecting to the original page with an additional queryfield, so I can give a nice error message (and still show the original page).
procedure TWebForm1.OnError(e: EventArgs); begin if (Server.GetLastError.GetBaseException is System.Web.HttpRequestValidationException) then begin Response.StatusCode := 200; Response.Redirect(Request.Url.ToString + '?Ex=42', True) end end;Note that the second argument to the Response.Redirect specifies if this means the end of the response, so we do not have to explicitly call Response.End again. In the Page_Load, I can now check for the Request.Params['Ex'] to see if an error was raised, so I should give the user a friendly error message instead.
if Request.Params['Ex'] = '42' then Response.Write('Sorry. no HTML allowed here!');Instead of using the low-level Response.Write you can also use a Label and set the Text here.What matters is that you tell the user that HTML is not allowed, and give the user a chance to re-enter the text.
In this short article, I’ve shown you a simple technique that will leave ASP.NET input validation (and script detection) intact, but will respond with a more friendly error message for the HttpRequestValidationException in case your visitors enter HTML or related text in your ASP.NET web forms. Note that the contents which was entered in the “invalid” request is gone, but so is the contents of the multi-line TextBox, since we did a Response.Redirect, so the entire ViewState is gone! But at least it’s better than the ugly error message we saw before.