ASP.NET MVC A potentially dangerous Request.Form value was detected from the client when using a custom modelbinder
Asked Answered
E

5

109

Getting the error here:

ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");

How do I allow on a selection of values only? i.e.

[ValidateInput(false)]
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
    ValueProviderResult value2 = bindingContext.ValueProvider.GetValue("ConfirmationMessage2");
}
Extracanonical answered 22/6, 2013 at 19:8 Comment(4)
Possible duplicate of A potentially dangerous Request.Form value was detected from the client, doesn't matter if it's Webforms or MVC.Omniscient
Thanks, but you havent looked at my issue as its differentExtracanonical
Same exact root problem, the only difference is there may be MVC specific ways to deal with it.Omniscient
When using EF, see bizzehdee answer here #17964813Badmouth
V
241

You have a few options.

On the model add this attribute to each property that you need to allow HTML - best choice

using System.Web.Mvc;

[AllowHtml]
public string SomeProperty { get; set; }

On the controller action add this attribute to allow all HTML

[ValidateInput(false)]
public ActionResult SomeAction(MyViewModel myViewModel)

Brute force in web.config - definitely not recommended

In the web.config file, within the tags, insert the httpRuntime element with the attribute requestValidationMode="2.0". Also add the validateRequest="false" attribute in the pages element.

<configuration>
  <system.web>
   <httpRuntime requestValidationMode="2.0" />
  </system.web>
  <pages validateRequest="false">
  </pages>
</configuration>

More info: http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

The above works for usages of the default modelbinder.

Custom ModelBinder

It appears that a call to bindingContext.ValueProvider.GetValue() in the code above always validates the data, regardless any attributes. Digging into the ASP.NET MVC sources reveals that the DefaultModelBinder first checks if request validation is required and then calls the bindingContext.UnvalidatedValueProvider.GetValue() method with a parameter that indicates if validation is required or not.

Unfortunately we can’t use any of the framework code because it’s sealed, private or whatever to protect ignorant devs from doing dangerous stuff, but it’s not too difficult to create a working custom model binder that respects the AllowHtml and ValidateInput attributes:

public class MyModelBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // First check if request validation is required
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;

        // Get value
        var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
        if (valueProviderResult != null)
        {
            var theValue = valueProviderResult.AttemptedValue;

            // etc...
        }
    }
}

The other required piece is a way to retrieve an unvalidated value. In this example we use an extension method for the ModelBindingContext class:

public static class ExtensionHelpers
{
    public static ValueProviderResult GetValueFromValueProvider(this ModelBindingContext bindingContext, bool performRequestValidation)
    {
        var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;
        return (unvalidatedValueProvider != null)
          ? unvalidatedValueProvider.GetValue(bindingContext.ModelName, !performRequestValidation)
          : bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    }
}

More info on this at http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/

Vickers answered 23/6, 2013 at 6:3 Comment(6)
i have this on the controller [HttpPost, ValidateInput(false)] and i still get the errorExtracanonical
See my revised answer with a way around this when using a custom modelbinderVickers
Thanks, but it does not like this line bindingContext.GetValueFromValueProviderExtracanonical
GetValueFromValueProvider needs to be in a public static class. Check out the edits above.Vickers
Ta, valueProviderResult reutrns null tho? var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);Extracanonical
How about a solution for when this error shows up not at the initial POST, but when trying to return a PartialView back to an ajax call. Also not using a custom Model binder on this type.Fontenot
E
35

Try:

HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")
Extracanonical answered 24/6, 2013 at 20:0 Comment(2)
When I try this, I get an exception which says: Non-invocable member 'System.web.HttpRequestBase.Unvalidated' cannot be used like a method. Has this thing changed?Lancers
The second line should really be var re = request.Unvalidated.Form["ConfirmationMessage"];Lancers
Z
7

Expanding upon the answer from @D-W, in my Edit controller, in iterating over form values, I had to replace all instances of Request.Params.AllKeys with Request.Unvalidated.Form.AllKeys and all instances of Request[key] with Request.Unvalidated.Form[key].

This was the only solution that worked for me.

Zoltai answered 28/2, 2017 at 17:12 Comment(0)
C
0

As Mike Godin wrote, even if you set [ValidateInput(false)] attribute, you have to use Request.Unvalidated.Form instead of Request.Form This worked for me with ASP.NET MVC 5

Cerelly answered 14/11, 2019 at 16:59 Comment(1)
This was actually a useful advice, as accessing data from a base controller (i.e. for log or debug purposes) any access to Request.Form throws exception even if the model has this attribute.Zomba
S
-4

Here are the steps to encode at client level and decode it at server level:

  1. Post the form using jquery submit method.

  2. In jquery button click event method encode field that you want to post to server. Example:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
    
  3. In Controller Level access all form id value using

    HttpUtility.UrlDecode(Request["fieldid"])
    

Sample example:

  • Controller level:

    public ActionResult Name(string id)
    {
    
        CheckDispose();
        string start = Request["start-date"];
        string end = Request["end-date"];
        return View("Index", GetACPViewModel(HttpUtility.UrlDecode(Request["searchid"]), start, end));
    }
    
  • Client level:

    <% using (Html.BeginForm("Name", "App", FormMethod.Post, new { id = "search-form" }))
    { %>
    <div>
    <label  for="search-text" style="vertical-align: middle" id="search-label" title="Search for an application by name, the name for who a request was made, or a BEMSID">App, (For Who) Name, or BEMSID: </label>
    <%= Html.TextBox("searchid", null, new {value=searchText, id = "search-text", placeholder = "Enter Application, Name, or BEMSID" })%>
    </div>
    <div>
    <input id="start-date" name="start-date" class="datepicker" type="text"  placeholder="Ex: 1/1/2012"/>
    </div>
    <div>
    <input id="end-date" name="end-date" class="datepicker" type="text"  placeholder="Ex: 12/31/2012"/>
    </div>
    <div>
    <input type="button" name="search" id="btnsearch" value="Search" class="searchbtn" style="height:35px"/>
    </div> 
    <% } %>
    

In Document Ready function:

$(function () {     
  $("#btnsearch").click(function () {  
    $("#search-text").val(encodeURIComponent($("#search-text").val()));
    $("#search-form").submit();
  });
});
Schadenfreude answered 1/7, 2014 at 9:14 Comment(2)
Jquery and client-side technology has nothing to do with MVC, the validation happens at server side with MVC framework. It's not a valid answerKnute
Given that Microsoft literally ignores the AllowHtml attribute, and given that the only workable solution server-side is to replace the functionality of the default model binder, I would argue that client-side encoding is a perfectly valid option.Holmic

© 2022 - 2024 — McMap. All rights reserved.