Last week while working on what amounts to my first website in a very long time, I stumbled across something I hadn’t seen before. I was working on a bug that allowed the input of script tags into free text fields. This was causing the browser to pop up various HTTP 500 errors. The answer as to why, lay in the stack trace.
What the good old trace told me was that my page was attempting to validate the HTTP request before it was sent to the server. It turned out the page was throwing a HTTPValidationException which due to the error model used was being swallowed by the page and subsequently presented as the more general HTTP 500 error. Below is the screen I would have got, had I not swallowed the error…
Now I knew what I was dealing with I went to take a look deeper into what was happening here. Down my stack trace there was a pointer to the Page.ProcessRequest method with the HTTPContext being passed in. What was going on was that when this method was called it was validating the request to ensure there was no potentially nasty hacker bits in there.
So – ASP.Net was being a good mother and making sure I couldn’t inadvertently hurt myself by allowing people to insert HTML tags into my text fields. Wow I thought, that’s pretty neat! As neat as it was though, I had to fix the error. So where to from here?
The next step was once again google. I came across a number of posts on the ASP.Net request validation process – I’ve linked a couple at the bottom that I think are worth a read, and in summary there is 2 ways you can handle this type of error.
1. Disable request validation on either a page by page, or application basis.
2. Handle the error gracefully in the Application_Error method of your global.asax file
Needless to say, they both have their merits. For my particular scenario, where I wanted to allow the widest possible range of input I chose to go with option 1. The problem with option 2 is that even if you do handle the error, the best you can do is hand the user back to their previous page, with or without their previously entered data and a warning not to be so naughty next time.
Even though I chose to disable the request validation in some of my pages, I still needed to cater for the possibility of script tags being inserted into text fields. Otherwise, I was vulnerable to various forms of scripting attacks. So what to do? The answer is really quite simple, use the HTTPUtility class member HtmlEncode (string Server.HtmlEncode(string)) to render the input back into it’s HTML equivalent. This converts all angled brackets into their < and > equivalents and renders any attempted script pretty much useless.
There is one last gotcha to be aware of… In some controls you will need to decode the HTML back into it’s character form. This can be done once again with the HttpUtility class member HtmlDecode (string Server.HtmlDecode(string)).
There are other approaches to solving this problem, and you should consider doing more than just the HTML conversion of input if you intend to turn off request validation at an application level. I suggest that you head over to the MSDN guide on preventing script injection attacks at least to take a look at some other approaches. That or let ASP.Net do your heavy lifting and validate all your requests for you!
1. Security Practices: ASP.NET 2.0 Security Practices at a Glance
2. How To: Protect From Injection Attacks in ASP.NET
3. ASP.NET Internals – IIS and the Process Model
4. Scott Hanselman’s ComputerZen.com