Overriding View model to sanitize string - c#

I have created a model binder to sanitize string property from malicious input using AntiXssEncoder.HtmlEncode for us to be able to save encoded string without worrying about XSS. So I have made this work, however, the only problem that I'm having and solving is how to Decode string property with AntiXss encoded the value.
The page render this text as see the below:
I want the page to render the text to <test> me instead of the above image. I tried to look to some resource to do this and can make this happen by adding an extension method to a string in the view. But this is tedious I want to set something global that automatically sanitize string properties in the model before rendering them on the page.
Could anyone suggest a way implement auto string sanitization globally or override the view model and check for string properties and sanitize them before rendering the page?
Update:
Or a way which I could override this part of ActionResult
public ActionResult Test()
{
return View(model);
}

The fact that your code isn't decoding it will depend on how you are implementing your model binder.
To decode you would normally just use HttpUtility.Decode, so you may have to run this somewhere.
It may be that you need to put the [AllowHtml] attribute onto your model properties.
Alternatively it may be that you need to implement IHtmlString somehow to make use of the ToHtmlString() method which lets you put html directly onto the page without MVC sanitising it automatically.
Possibly some more code would make it clearer but one of those three should point you in the right direction.

Related

Binding to a name that is not a legal C# variable name

I'm using the Google ReCaptcha element on a form. ReCaptcha adds a parameter to the POSTed parameters named g-recaptcha-response, which the controller needs to retrieve. Since this parameter name is not a legal C# variable name, it seems that the only way to retrieve its value is via Request.Params["g-recaptcha-response"] (rather than via model binding to a property in the view model).
Now, my problem is that elsewhere in the POSTed parameters I have a couple of form fields that may contain HTML markup. I have annotated the associated properties in my view model with [AllowHtml], which prevents the model binder from throwing an HttpRequestValidationException if the user enters HTML markup into the form. But [AllowHtml] apparently only works in the model binder. If the user has entered HTML markup into the form, then I get an HttpRequestValidationException when I reference Request.Params to fetch the ReCaptcha response.
As near as I can tell, the only way I can fetch the ReCaptcha response while still allowing HTML markup in selected POST parameters is to use go through the pain of writing a custom model binder (e.g. https://stackoverflow.com/a/4316327/1637105) to allow me to bind a property in my view model to an alias (in my case, a property name that is not a valid C# variable name).
The point of this question is just to confirm that I really do need to go to the pain of implementing a custom model binder.
Any suggestions or alternate solutions are more than welcome!
EDIT:
It occurs to me that another solution would be to figure out a way to fetch the value from the POSTed parameters without triggering (or while handling) the HttpRequestValidationException.
You can use the Unvalidated property of Request to access values without triggering Request Validation. for example
var captcha = Request.Unvalidated.Form["g-recaptcha-response"];

Output HTML from ToString without using #Html.Raw

I have a custom collection which holds messages for my view. I have overriden the ToString method so that it returns valid HTML. This allows it to be be easily referenced in the view.
#Model.Messages
Unfortunately the HTML is being encoded.
I know that for properties you can return an IHtmlString but that would require a wrapper property (something like #Model.Messages.Render) I also know that in the view I can use #Html.Raw to prevent the encoding but isn't there a way to inform the view that the ToString method returns a proper HTML string. Perhaps through data annotations?
I feel as though I'm having to add additional clutter to my view which I would rather encapsulate in my model.
What about using HttpUtility.HtmlDecode()
#HttpUtility.HtmlDecode(Model.Messages)

Should View Models always contain the inputs for forms in that view?

This question is related to this one, but I think in my example I have detail which may alter answers.
Say I have a User action on a Controller that renders a View for displaying data about a particular User, it might have a UserViewModel like so:
public class UserViewModel {
public string FirstName;
public string LastName;
etc...
}
However, in this View, as well as showing this user data, I want to have a search textbox for the user so they can look up another user on this page. This form would post into an action of FindUser, which accepts the following model:
public class FindUserInputViewModel {
[Required]
public string SearchQuery;
}
If this action finds the model to be invalid, it redirects back to the User action, maintaining the ModelState.
Now, currently to show the validation error, I cannot use a strongly-typed helper as that search query property isn't in UserViewModel, I'd have to do this:
#Html.TextBox("SearchQuery")
#Html.ValidationMessageFor("SearchQuery")
This works, and the error will be displayed, as well as the old value that was POSTed being shown (as it is persisted in the ModelState). However, I'd prefer to use a strongly-typed helper wherever possible.
From all the examples I have seen, the pattern here seems to be that the UserViewModel should contain the FindUserInputViewModel inside it, perhaps as an FindUserInput property. I could then do:
#Html.TextBoxFor(m => m.FindUserInput.SearchQuery)
This also works, as long as I make sure my FindUser action binds to the correct prefix, or I specify a name in the TextboxFor method call.
However, I don't really see why my UserViewModel should contain this other ViewModel simply for the case of binding the validation using this helper. Does it bring other benefits that I am not seeing? I understand the use of it if your View's model is needing to render out the same data you are posting, such as on a typical Edit action, but that isn't the case here.
It looks like to me that what would be handy here is a another generic helper that can reference a different type, something like this:
#Html.TextBoxForType<FindUserInput>(m => m.SearchQuery)
This doesn't exist, but I think I should be able to write that, and this is a good case for one. Does that sound like an appropriate solution, or am I missing something here?
Another option entirely is perhaps that the small-form for posting in that FindUserInputViewModel should have its own GET action as well as POST, and then the User View can just call into it using #Html.Action. It could then render a partial-view that is only strongly typed to FindUserInputViewModel.
Why not create a partial view for your search and simply pass this a new FindUserInputViewModel from your user view?
#Html.Partial("FindUser", new FindUserInputViewModel())
You can type your partial view to FindUserInputViewModel and use strongly-typed helpers in there. I'd say this is the simplest and neatest approach, unless there's something I'm missing?

Always output raw HTML using MVC3 and Razor

I’ve got a class with a property that looks like this:
[AllowHtml]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
I’ve already put in the [AllowHtml] attribute to let me submit HTML to this property via the form that I’ve built, but what I want to do is output the value of the property as the raw HTML without it being escaped.
I know I can use Html.Raw(Model.Description) but what I’m looking for is some way of telling Html.DisplayFor(m => m.Description) to always output the raw HTML. Is there an attribute I can use to decorate the properties in my class that I wish to behave like that?
Basically it’s me being lazy—I don’t want to have to remember which properties might contain HTML, so I don’t want to have to think about using Html.Raw(…) when I need to do the above—I’d much rather my Model know what it should do and do it automatically. I’ve tried searching for an answer, but either I’m not phrasing it correctly or there’s no way of doing it :(
Thanks,
Change your Description proerpty to return an HtmlString.
Razor does not escape HtmlString values.
(In fact, all Html.Raw does is create an HtmlString)
This is actually rather simple (once you know how...). Change your DataType attrib to [DataType(DataType.Html)], and create a partial view, put it in Views/Shared/DisplayTemplates/Html.cshtml, with this:
#model string
#Html.Raw(Model)
Of course you can also not change your DataType attrib, and name the view MultilineText.cshtml instead of Html.cshtml.
Just to provide a bit more info here - your issue is that # will always HtmlEncode unless you have IHtmlString returned - so the issue is sourced at the # symbol. It's one of the benefits of the razor syntax - its safer to htmlencode than to not. So there is no 'quick' way here since the root of your issue is the # symbol which will exclude HtmlEncoding if it finds IHtmlString. So - no 'quick' way around this unless you use the old <% syntax which IMHO sucks compared to razor : )

How to populate strongly typed viewdata from a base controller?

All my controllers are based off of a BaseController, to share properties between them and override OnActionExecuting to set some values based on the route.
I'm creating a BaseViewData class to do the same for all my view data.
At the moment I'm populating the view data like so (C#):
var viewData = new BaseViewData
{
Name = "someName",
Language = "aLanguage",
Category = "aCategoryName"
};
I do this in every action that requires the view data. Some of the properties are common, need to be set throughout every action. Is there a way to set some of the properties on a more global scale?
If I instantiate the BaseViewData class in the OnActionExecuting method on the BaseController, how do I access the BaseViewData properties from the action in the regular controllers (derived from the BaseController)?
Update in response to Dennis Palmer:
I'm essentially doing this because of a nagging issue I'm having with ViewData["lang"] not being populated randomly on some requests. ViewData["lang"] contains "en" if the language is English, and "ja" if it is Japanese (well, it's supposed to anyway). I populate ViewData["lang"] inside OnActionExecuting on the BaseController.
In my view, I make a call to some partial views based on the language:
<% Html.RenderPartial(ViewData["lang"] + "/SiteMenu"); %>
But I'm randomly getting errors thrown that state "Cannot find /SiteMenu", which points to the fact that ViewData["lang"] has no value. I just cannot find any reason why ViewData["lang"] would not get populated. So, I'm rewriting the site to use ONLY strongly typed view data (and setting some hard defaults). But if another method is better, I'll go that way.
Thank you!
I'm not sure I follow exactly what you're trying to do, but if your view is using values in the route to display certain information, it seems like adding your own extension methods for HtmlHelper would be a better way to go.
Are Name, Language and Category contained in your routes? If so, then HtmlHelper will have access to the route info and can determine what to display via the extension methods. What is the correlation between your routes and what your views need to know?
Update: Is lang part of your route? If so, then I would still contend that you could write an HtmlHelper extension method that looks at the route data directly and determines which partial view to render. That way your controller wouldn't even need to worry about setting the ViewData["lang"]. The view would always know how to render based on the route.
Update 2: I think dismissing use of an HtmlHelper extension method because it re-evaluates the route data might be a case of premature optimization. Your controller inheritance scheme sounds overly complex and you asked the question because the way you were setting ViewData was unreliable. I doubt that pulling the value from route data would be much, if any, less efficient than setting and reading from ViewData.
From your comment:
In the controller I use the lang value
to determine which view to show as
well.
That only makes me think that there are more pieces of your system that I'd need to see in order to give better advice. If you have separate views for each language then why does the view need to be told which language to use?
Another alternative to consider would be using nested master pages. You could have a single master page for your site layout and then a nested master page for each language that just contains a hard coded lang value.
Perhaps instead of this inheritance scheme you have, you can just use action filters to add the data you need.

Categories