Monday, April 4, 2011

MVC3 XSS Protection

I am focusing quite a bit on security in my current project, and so I decided to spend a little time working with the default xss projection in MVC3.

On the surface, it seems as if the default protection against XSS is quite robust in MVC3.  I started off by creating a simple form that took a message input.  This message was added to the ViewData and passed back to another view where it was displayed.  I tried the most basic of XSS attacks at got a nice little error message saying

Server Error in '/' Application.

A potentially dangerous Request.Form value was detected from the client (message="<script>alert("hello...")

Pretty good eh?  Now of course you would want to have a custom error page all set up, but this is quite nice protection to have right out of the box.  MVC3 includes a ValidatinInputAttribute which you can set to false to disable the input validation.  You can set this attribute only on the method or class level, so make sure you know what you are doing.

        public ActionResult Display(string message)

Adding this attribute on to my method got rid of the nasty error message received before.  I proceeded to add this message directly to the ViewData and outputted it directly on the screen.  To my amazement, it printed the input with the proper escaping!  WOW!  Microsoft finally got something right.  I started to ask myself the question, what if I actually wanted to display HTML on the screen, say for example, rich text input.  It turns out that you have to do a combination of the following.

In you model input, you have to use the AllowHtmlAttribute.  This attribute will ensure that you won't get a nasty message when input validation occurs without having to disable all field validation for that method or class.  This also allows you to still do some sanity checks on the data you are receiving.  In order to get this html to display properly, you have to use the Html.Raw method to output the data.

public class DisplayModel
        public string Message { get; set; }

Hello, @Html.Raw(Model.Message)

It is good to see that it MVC3 is trying to do protection by default.