ASP.NET MVC Потенциально опасное значение Request.Form было обнаружено от клиента при использовании настраиваемого связывания моделей

96

Получение ошибки здесь:

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");
}
DW
источник
1
Возможный дубликат потенциально опасного значения Request.Form был обнаружен от клиента , не имеет значения, веб-формы это или MVC.
Эрик Филипс
2
Спасибо, но вы не рассматривали мою проблему как другую
DW
Та же самая корневая проблема, с той лишь разницей, что для ее решения могут быть специфические способы MVC.
Эрик Филипс
При использовании EF см. Ответ bizzehdee здесь stackoverflow.com/questions/17964313/…
Петр

Ответы:

227

У вас есть несколько вариантов.

В модели добавьте этот атрибут к каждому свойству, которое необходимо для разрешения HTML - лучший выбор.

using System.Web.Mvc;

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

В действии контроллера добавьте этот атрибут, чтобы разрешить весь HTML

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

Брутфорс в web.config - не рекомендуется

В файле web.config внутри тегов вставьте элемент httpRuntime с атрибутом requestValidationMode = "2.0". Также добавьте атрибут 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

Похоже, что вызов 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/

ericdc
источник
у меня есть это на контроллере [HttpPost, ValidateInput (false)], и я все еще получаю сообщение об ошибке
DW
См. Мой пересмотренный ответ, в котором есть способ обойти это при использовании специального связывателя моделей
ericdc
Спасибо, но ему не нравится эта строка bindingContext.GetValueFromValueProvider
DW
GetValueFromValueProvider должен находиться в общедоступном статическом классе. Проверьте правки выше.
ericdc
Ta, valueProviderResult возвращает null tho? var valueProviderResult = bindingContext.GetValueFromValueProvider (shouldPerformRequestValidation);
DW
31

Пытаться:

HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")
DW
источник
Когда я пытаюсь это сделать, я получаю исключение, в котором говорится: Невызываемый элемент System.web.HttpRequestBase.Unvalidated не может использоваться как метод. Эта вещь изменилась?
Stack0verflow
7
Вторая строка действительно должна бытьvar re = request.Unvalidated.Form["ConfirmationMessage"];
Stack0verflow
5

Расширение на ответ от @DW, в моем редактировании контроллера в итерация значений формы, мне пришлось заменить все экземпляры Request.Params.AllKeysс Request.Unvalidated.Form.AllKeysи всеми экземплярами Request[key]с Request.Unvalidated.Form[key].

Это было единственное решение, которое сработало для меня.

Майк Годин
источник
0

Как писал Майк Годин, даже если вы установили атрибут [ValidateInput (false)], вам нужно использовать Request.Unvalidated.Form вместо Request.Form. Это сработало для меня с ASP.NET MVC 5

Ryozzo
источник
1
На самом деле это был полезный совет, так как при доступе к данным из базового контроллера (т.е. для целей журнала или отладки) любой доступ к Request.Form вызывает исключение, даже если модель имеет этот атрибут.
nsimeonov
-4

Вот шаги для кодирования на уровне клиента и декодирования на уровне сервера:

  1. Опубликуйте форму, используя метод отправки jquery.

  2. В jquery нажмите кнопку метода события, закодируйте поле, которое вы хотите отправить на сервер. Пример:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
    
  3. На уровне контроллера доступ ко всем значениям идентификатора формы с помощью

    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. Это
неверный
2
Учитывая, что Microsoft буквально игнорирует атрибут AllowHtml, и учитывая, что единственное работоспособное решение на стороне сервера - это замена функциональности связывателя модели по умолчанию, я бы сказал, что кодирование на стороне клиента является совершенно допустимым вариантом.
Джонатан