The MvcHtmlString class:
Represents an HTML-encoded string that should not be encoded again. This class contains some interesting methods from security perspective like:
Create | Creates an HTML-encoded string using the specified text value. |
ToHtmlString | Returns an HTML-encoded string that represents the current object. |
The MvcHtmlString.Create method:
The Create method of the MvcHtmlString class in System.Web.Mvc namespace creates an HTML-encoded string using the specified text value in the parameter.
The method signature for the Create method is:
The <%: %> code syntax for the MVC ASPX engine:
<%: %> is a new syntax for HTML Encoding output in ASP.NET 4 and ASP.NET MVC 2. This syntax renders output like <%= %> blocks do, but at the same time, also automatically HTML encodes it before rendering.
Considering that ASP.NET 4 introduced a new IHtmlString interface (along with a concrete implementation: HtmlString) that a developer can implement on types to indicate that its value is already properly encoded for displaying as HTML, and that therefore the value should not be HTML-encoded again, a possibility of Double Encoding arises when <%:%> and instances of IHtmlString are used together.
To avoid this, <%: %> code-nugget syntax checks for the presence of the IHtmlString interface implementation and will not HTML encode the output of the code expression if its value implements this interface.
The @model.<…> syntax for the MVC Razor engine:
This syntax automatically encodes value that is represented by <…>. Only exceptions will be when <…> is of MvcHtmlString type.
Possible permutations:
<%: MvcHtmlString %> | <%:%> will not encode the MvcHtmlSTring to avoid double encoding as this is assumed to be already encoded |
<%: NormalString %> | <%:%> will Html encode the NormalString before rendering the same. |
@model. <somethingNonMvcHtmlString> | This will be HTML encoded and rendered. |
@model. <somethingMvcHtmlString> | This will be not get HTML encoded as this is assumed to be already encoded somethingMvcHtmlString is already assumed to be encoded. |
So why document these when these details are already available in MSDN/TechNet/web?
Because MvcHtmlString.Create method is not generating an HTML-encoded string as documented. And when these strings gets rendered within the <%:%> or @model.<…> syntax, they are not encoded and as a result a non-encoded string gets rendered into the browser.
Demo:
A small MVC 3 application is created just to check the workings of the Create method of MvcHtmlString class.
The application takes a user string and renders it into the browser. It provides us an option to render as a normal string or as a HtmlMvcString. The UI looks as below:
Once I click on Test, the content entered is rendered as below:
The view code that handles this rendering part is:
The strUserString is a normal string object.
The data model to which this view is bound has the following code:
Now to check the encoding behaviour, we pass some script values and try to render it in the browser.
Behaviour for Normal String:
This text is encoded and rendered as below:
Now the same text is rendered as an MvcHtmlString type:
The output looks as below:
The MvcHtmlString.Create method did not encode the string as documented. This needs to be taken care of during code reviews particularly when values of type MvcHtmlString is rendered within the <%: %> code nugget expressions or in @Model.<…> in ASP.NET 4 and ASP.NET MVC 2 onwards.
<%: %> and @Model.<…> will NOT automatically encode an object of type MvcHtmlString.
Some points to keep in mind when reviewing ASP.NET 4 and ASP.NET MVC onwards:
1. Check for <%: %> and MvcHtmlString usage.
2. Check for @Model.XXXX and MvcHtmlString usage
3. If found, check the type of value that is being rendered between the <%: %> code nugget expressions. Same for @Model.XXXX
4. If the type is normal string, <%: %>/@Model.XXXX will HTML encode the value. But if the type is MvcHtmlString then the value rendered within <%: %> will not be encoded. So if you see <%: %> in code do not assume that every value within it is encoded by default.
References:
1. http://weblogs.asp.net/scottgu/archive/2010/04/06/new-lt-gt-syntax-for-html-encoding-output-in-asp-net-4-and-asp-net-mvc-2.aspx
2. http://stevesmithblog.com/blog/default-encoding-of-strings-in-asp-net-mvc-2/