Wednesday, January 09, 2008

Be careful outputting strings in ASP.NET MVC

During my presentation at Alamo Coders last night, someon mentioned that it is unsafe to output user-entered strings like this:

<h2><%= college.Name %></h2>

The reason is, of course, that the user could be malicious and enter in a string such as this:

“<script>alert(‘I am evil’);</script>”

And it would evaluated on the page and all of your users would get an alert box.  This is leaving your door wide-open to clever attacks known as Cross Site Scripting and is very dangerous.

Instead, we should escape these strings so that they aren’t rendered as HTML or javascript, but rather textual characters.  That means that < will be translated to &lt; and so on.

To do that, the Html helpers that ship with the framework give you an Encode method, letting you do something like:

<h2><%= Html.Encode(college.Name) %></h2>

But the syntax is a bit cumbersome for every outputted value on a page.  I prefer the way Rails handles it… like this:

<h2><%= h(college.Name) %></h2>

And it turns out that you can add this extension method somewhere and be done with it:

public static string h(this ViewPage page, string input)
{
     return new HtmlHelper(page.ViewContext).Encode(input);
}
And that’s it!  Just remember to take this precaution, or you’ll regret it later.
Wednesday, January 09, 2008 9:46:55 PM (Central Standard Time, UTC-06:00)
This raises the question as to whether one should be stripping these values from the input before you insert it into your database. It takes a little bit of extra processing and if you are already performing some type of validation it isn't that much more difficult.

Although, I've heard people discuss it either way to no end on newsgroups before so I won't say for one way or the other. Even if you are stripping nasty values before insertion into the database, this is an added bonus to be positive that you are not outputting anything nasty.
Wednesday, January 09, 2008 10:13:27 PM (Central Standard Time, UTC-06:00)
I am debating if this should be in the convention controller? Or just derive yet another controller from the convention controller? Or can you decorate the property on the model with something like [HtmlEncode] and when ever there is an assignment to a view you intercept the assignment and automatically encode it? hmmm... Thoughts?
Thursday, January 10, 2008 6:55:20 AM (Central Standard Time, UTC-06:00)
@Joe: Yes, making that a convention is tempting, but I'd rather be in control. For one thing, it will slow down your rendering.

@Sean: Indeed, if we are in control of the input.
Thursday, January 10, 2008 3:21:03 PM (Central Standard Time, UTC-06:00)
I like handling this at various domain layers. When I'm communicating from the page to the business domain, I'll un-escape the HTML for a variety of reasons, the biggest being database field lengths. If I have the input <something> it's 11 characters, but when I HtmlEncode it, each < becomes three characters, so it's actually 17 characters, so if that field is limited to 12 characters, then you're going to get an error and detecting this and dealing with it is not fun. Therefore, I think of every single string that goes into the domain (typically from the controller or presenter) as unsafe and always convert. If a string is going out of the business domain, I'll HtmlEncode it, which guarantees that user input will always be ok and that I won't overflow any field lengths (the obvious potential exception to this is xml data but if you handle input before you insert it into and xml doc you should still be fine. If you're writing an xml editor or an html editor, then none of this applies). I think Joel Spolsky mentioned using a coding convention where he prefixed strings with either a 'u' or 's' depending on if it was safe or unsafe, so anytime you'd set a value from a variable, you could tell if it's safe or not, and anything like "sOutput = uVariable" was code smell.
Wednesday, January 16, 2008 2:10:06 PM (Central Standard Time, UTC-06:00)
I was at your talk at the FWDNUG last night -- I was the guy in the gray sweater in the first row -- your talk was really great and easy to follow. I'm glad I stumbled across this post on your blog, 'cause I meant to ask you about XSS in MVC during the break. The extension method here is a first-class idea.

Thanks again for an engaging, entertaining presentation!
Comments are closed.
Loans - Credit Card - Mortgages - Scottsdale Landscaping