0

This is a view:

@model ModelValidation.Models.Appointment
@{
    ViewBag.Title = "Make a Booking";
}
<h2>
    Book an Appointment</h2>
@using (Html.BeginForm())
{
    <p>
        @Html.LabelFor(m => m.ClientName, "Your name: ") @Html.EditorFor(m =>     m.ClientName)    
    </p>
    <p>
        @Html.LabelFor(m => m.Date, "Appointment Date: ") @Html.EditorFor(m => m.Date)        
    </p>
    <p>
        @Html.EditorFor(m => m.TermsAccepted) @Html.LabelFor(m => m.TermsAccepted, "I     accept the terms & conditions")
    </p>
    <input type="submit" value="Make Booking" />
}

This is the Appointment class:

public class Appointment
{
    public string ClientName { get; set; }

    [DataType(DataType.Date)]
    public DateTime Date { get; set; }

    public bool TermsAccepted { get; set; }
}

If I enter into the ClientName editor something like this:

<b>asdf</b>

after I press the "Make Booking" button (submit) I get the following exception:

[HttpRequestValidationException (0x80004005): potentilly dangerous value of Request.Form has been received from the client (ClientName="<b>asdf</b>").]
   System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8755668
   Microsoft.Web.Infrastructure.DynamicValidationHelper.<>c__DisplayClass12.<ReplaceCollection>b__d(String value, String key) +79
   Microsoft.Web.Infrastructure.DynamicValidationHelper.LazilyEvaluatedNameObjectEntry.ValidateObject() +89
   Microsoft.Web.Infrastructure.DynamicValidationHelper.LazilyValidatingHashtable.get_Item(Object key) +54
   System.Collections.Specialized.NameObjectCollectionBase.FindEntry(String key) +20
   System.Collections.Specialized.NameValueCollection.GetValues(String name) +8
   System.Web.Mvc.ValueProviderResultPlaceholder.GetResultFromCollection(String key, NameValueCollection collection, CultureInfo culture) +20
   System.Web.Mvc.<>c__DisplayClass4.<.ctor>b__0() +16
   System.Lazy`1.CreateValue() +361
   System.Lazy`1.LazyInitValue() +9591042
   System.Lazy`1.get_Value() +89
   System.Web.Mvc.NameValueCollectionValueProvider.GetValue(String key, Boolean skipValidation) +68
   System.Web.Mvc.ValueProviderCollection.GetValueFromProvider(IValueProvider provider, String key, Boolean skipValidation) +55
   System.Web.Mvc.<>c__DisplayClass9.<GetValue>b__4(IValueProvider provider) +33
   System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +151
   System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +177
   System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source) +4187840
   System.Web.Mvc.ValueProviderCollection.GetValue(String key, Boolean skipValidation)     +272
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +385
   System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) +17
   System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) +399
   System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) +93
   System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +53
   System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1367
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +449
   System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +317
   System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +117
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
   System.Web.Mvc.Controller.ExecuteCore() +116
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
       System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8862381
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

As far as I know all the user input is encoded by default in razor view engine. Then why am I getting this?

The exception is thrown before the target POST action method is invoked. Or what am I missing?

horgh
  • 17,918
  • 22
  • 68
  • 123
  • 1
    Do you want the `ClientName` to be encoded? Razor encodes html when it is *rendered*, not when you supply it as an input. If you do want the html as it is then add a `ValidateInput(false)` over your controller or class. – gideon Aug 30 '12 at 05:38
  • I'm still new to web...what is correct approach then? To encode it before submit? Or to check it myself in a post action method? Is there kind of best practise for this? – horgh Aug 30 '12 at 05:40

2 Answers2

4

Edit:

Sorry read that all wrong.

The MVC framework by default will try and protect you from dangerous input, such as html. This can be used to attack your site if you later re-render it. See Cross Site Scripting

If you want to accept HTML like the value you are entering for the name, you will have to explicitly tell it not to validate that input.

Like:

[HttpPost]
[ValidateInput(false)]
public ActionResult Save()
{
    // ...method body
}

I would of course recommend against this unless it is a specific requirement.

shenku
  • 11,969
  • 12
  • 64
  • 118
  • Yes clean your data ! Don't store data with html in your data layer. In the future you will want to use ClientName elsewhere without format and you will have a problem. – Michal Franc Aug 30 '12 at 05:42
  • Does this attribute turn off any validation of the method parameters of the action method? – horgh Aug 30 '12 at 05:43
  • Is the following approach correct: either let framework throw an exception on such errors, or turn off validation, and check everything on my own..and decide what to do with such kind of data by myself? – horgh Aug 30 '12 at 05:45
  • As per msdn 'Request validation works by checking all input data against a hard-coded list of potentially dangerous data' – shenku Aug 30 '12 at 05:46
  • 1
    Let the framework do its job and throw the exception if someone tries to enter something bad. Only turn it off if you specifically NEED to accept HTML (and take steps to prevent attacks later on). Rather accept standard text as the input and style it yourself. Rather than have the user do it. – shenku Aug 30 '12 at 05:48
  • Nothing wrong with storing HTML in your data layer if the requirements allow for it. It does increase the attack surface but can be mitigated fairly decently. – Adam Tuliper Aug 30 '12 at 05:51
  • 1
    Shenku that was for the " Don't store data with html in your data layer" - however I have to disagree here on this approach. You should _NEVER_ use ValidateInput(false) unless there is a strong strong reason to do so. You should granularly use AllowHtml to allow specific fields otherwise you shutoff all checks - which is bad. People coming to this post will think its ok to turn off entire validation - which is bad : ) – Adam Tuliper Aug 30 '12 at 15:34
2

There isn't technically anything wrong with storing HTML in your data layer but it can increase your with of xss (cross site scripting) attacks with malicious HTML/script.

Use the

[AllowHtml]
attribute on your ClientName property. Then prior to save use the anti-xss library from Microsoft WPL or Web Protection Library and use the
Sanitizer.GetSafeHtmlFragment(clientName)
to sanitize it (not encode!) before saving to your database.

If you want much more extended information on request validation and xss attacks see my pluralsight.com hack proofing course.

gideon
  • 19,329
  • 11
  • 72
  • 113
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71