ASP.NET MVC使用自定义Modelbinder时从客户端检测到潜在危险的Request.Form值


95

在这里得到错误:

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

如何只允许选择值?即

[ValidateInput(false)]
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
    ValueProviderResult value2 = bindingContext.ValueProvider.GetValue("ConfirmationMessage2");
}

1
从客户端检测到潜在危险的Request.Form值的可能重复项,无论是Webforms还是MVC都无关紧要。
Erik Philips

2
谢谢,但您尚未将我的问题视为与众不同
DW

完全相同的根本问题,唯一的区别是可能存在MVC特定的处理方式。
Erik Philips

当使用EF,在这里看到bizzehdee答案stackoverflow.com/questions/17964313/...
切赫

Answers:


223

您有几种选择。

在模型上,将此属性添加到允许HTML所需的每个属性中- 最佳选择

using System.Web.Mvc;

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

在控制器操作上,添加此属性以允许所有HTML

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

web.config中的暴力破解- 绝对不建议

在web.config文件的标记内,插入带有属性requestValidationMode =“ 2.0”的httpRuntime元素。还要在pages元素中添加validateRequest =“ false”属性。

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

更多信息:http : //davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

以上适用于默认modelbinder的用法。

自定义ModelBinder

似乎在上面的代码中对bindingContext.ValueProvider.GetValue()的调用始终会验证数据,而不考虑任何属性。深入研究ASP.NET MVC源,可以发现DefaultModelBinder首先检查是否需要验证请求,然后使用指示是否需要验证的参数调用bindingContext.UnvalidatedValueProvider.GetValue()方法。

不幸的是,我们不能使用任何框架代码,因为它们是密封的,私有的或用于保护无知的开发人员避免从事危险工作的任何方法,但是创建一个尊重AllowHtml和ValidateInput属性的有效的自定义模型绑定程序并不难:

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...
        }
    }
}

另一个必需的部分是检索未验证值的方法。在此示例中,我们对ModelBindingContext类使用扩展方法:

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);
    }
}

有关更多信息,请访问http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/


我在控制器[HttpPost,ValidateInput(false)]上有此错误,但仍然收到错误
DW

使用自定义Modelbinder时,请参阅我的修订后的解决方法
ericdc 2013年

谢谢,但它不喜欢此行bindingContext.GetValueFromValueProvider
DW

GetValueFromValueProvider需要在公共静态类中。查看上面的修改。
ericdc 2013年

Ta,valueProviderResult是否为null?var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
2013年

30

尝试:

HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")

当我尝试此操作时,出现一个异常:不可使用的成员'System.web.HttpRequestBase.Unvalidated'不能像方法一样使用。这件事变了吗?
Stack0verflow

7
第二行应该确实是var re = request.Unvalidated.Form["ConfirmationMessage"];
Stack0verflow 2014年

4

扩展@DW的答案,在我的Edit控制器中,在遍历表单值时,我不得不替换了Request.Params.AllKeyswith的Request.Unvalidated.Form.AllKeys所有实例和Request[key]with的所有实例Request.Unvalidated.Form[key]

这是唯一对我有用的解决方案。


0

正如Mike Godin所写,即使您设置了[ValidateInput(false)]属性,也必须使用Request.Unvalidated.Form而不是Request.Form 这对于ASP.NET MVC 5来说对我有用


1
这实际上是一个有用的建议,因为从基本控制器访问数据(即出于日志或调试目的)对Request.Form的任何访问都会引发异常,即使模型具有此属性也是如此。
nsimeonov

-5

以下是在客户端级别进行编码并在服务器级别对其进行解码的步骤:

  1. 使用jquery Submit方法发布表单。

  2. 在jquery按钮中,单击要发布到服务器的事件方法编码字段。例:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
    
  3. 在控制器级别中,使用以下命令访问所有表单ID值

    HttpUtility.UrlDecode(Request["fieldid"])

示例示例:

  • 控制器级别:

    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));
    }
    
  • 客户等级:

    <% 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> 
    <% } %>
    

在“文档就绪”功能中:

$(function () {     
  $("#btnsearch").click(function () {  
    $("#search-text").val(encodeURIComponent($("#search-text").val()));
    $("#search-form").submit();
  });
});

4
jQuery和客户端技术与MVC无关,验证是通过MVC框架在服务器端进行的。这不是一个有效的答案
diegosasw 2015年

1
鉴于Microsoft实际上忽略了AllowHtml属性,并且鉴于服务器端唯一可行的解​​决方案是替换默认模型绑定程序的功能,因此我认为客户端编码是一个完全有效的选择。
乔纳森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.