ASP.NET MVC Um valor Request.Form potencialmente perigoso foi detectado do cliente ao usar um modelbinder personalizado


95

Obtendo o erro aqui:

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

Como posso permitir apenas uma seleção de valores? ie

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

1
Possível duplicata de Um valor Request.Form potencialmente perigoso foi detectado do cliente , não importa se é Webforms ou MVC.
Erik Philips

2
Obrigado, mas você não considerou meu problema como sendo diferente
DW

Exatamente a mesma raiz do problema, a única diferença é que pode haver maneiras específicas do MVC de lidar com ele.
Erik Philips

Ao usar EF, consulte a resposta de bizzehdee aqui stackoverflow.com/questions/17964313/…
Petr,

Respostas:


223

Você tem poucas opções.

No modelo, adicione este atributo a cada propriedade que você precisa para permitir HTML - melhor escolha

using System.Web.Mvc;

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

Na ação do controlador, adicione este atributo para permitir todo o HTML

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

Força bruta em web.config - definitivamente não recomendado

No arquivo web.config, dentro das tags, insira o elemento httpRuntime com o atributo requestValidationMode = "2.0". Adicione também o atributo validateRequest = "false" no elemento pages.

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

Mais informações: http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

O acima funciona para usos do modelbinder padrão.

Custom ModelBinder

Parece que uma chamada para bindingContext.ValueProvider.GetValue () no código acima sempre valida os dados, independentemente de quaisquer atributos. Investigar as fontes ASP.NET MVC revela que o DefaultModelBinder primeiro verifica se a validação da solicitação é necessária e, em seguida, chama o método bindingContext.UnvalidatedValueProvider.GetValue () com um parâmetro que indica se a validação é necessária ou não.

Infelizmente, não podemos usar nenhum código do framework porque ele é selado, privado ou qualquer outra coisa para proteger desenvolvedores ignorantes de coisas perigosas, mas não é muito difícil criar um fichário de modelo personalizado funcional que respeite os atributos AllowHtml e 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...
        }
    }
}

A outra parte necessária é uma forma de recuperar um valor não validado. Neste exemplo, usamos um método de extensão para a classe 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);
    }
}

Mais informações sobre isso em http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/


eu tenho isso no controlador [HttpPost, ValidateInput (false)] e ainda recebo o erro
DW

Veja minha resposta revisada com uma maneira de contornar isso ao usar um modelbinder personalizado
ericdc

Obrigado, mas não gosta desta linha bindingContext.GetValueFromValueProvider
DW

GetValueFromValueProvider precisa estar em uma classe pública estática. Confira as edições acima.
ericdc

Ta, valueProviderResult reutrns null tho? var valueProviderResult = bindingContext.GetValueFromValueProvider (shouldPerformRequestValidation);
DW

31

Experimentar:

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

Quando tento fazer isso, recebo uma exceção que diz: O membro não invocável 'System.web.HttpRequestBase.Unvalidated' não pode ser usado como um método. Essa coisa mudou?
Stack0verflow

7
A segunda linha realmente deveria servar re = request.Unvalidated.Form["ConfirmationMessage"];
Stack0verflow

5

Expandindo a resposta de @DW, em meu controlador de edição, na iteração sobre os valores do formulário, tive que substituir todas as instâncias de Request.Params.AllKeyscom Request.Unvalidated.Form.AllKeyse todas as instâncias de Request[key]com Request.Unvalidated.Form[key].

Essa foi a única solução que funcionou para mim.


0

Como Mike Godin escreveu, mesmo se você definir o atributo [ValidateInput (false)], você deve usar Request.Unvalidated.Form em vez de Request.Form Isso funcionou para mim com a ASP.NET MVC 5


1
Este foi realmente um conselho útil, como acessar dados de um controlador de base (ou seja, para fins de registro ou depuração), qualquer acesso a Request.Form lança uma exceção, mesmo se o modelo tiver este atributo.
nsimeonov

-5

Aqui estão as etapas para codificar no nível do cliente e decodificá-lo no nível do servidor:

  1. Publique o formulário usando o método jquery submit.

  2. No botão jquery, clique no campo de codificação do método do evento que você deseja postar no servidor. Exemplo:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
    
  3. No nível do controlador, acesse todos os valores de id de formulário usando

    HttpUtility.UrlDecode(Request["fieldid"])

Exemplo de amostra:

  • Nível do controlador:

    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));
    }
  • Nível do cliente:

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

Na função Document Ready:

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

4
Jquery e a tecnologia do lado do cliente não têm nada a ver com MVC, a validação acontece no lado do servidor com o framework MVC. Não é uma resposta válida
diegosasw

1
Dado que a Microsoft literalmente ignora o atributo AllowHtml, e dado que a única solução viável do lado do servidor é substituir a funcionalidade do fichário de modelo padrão, eu argumentaria que a codificação do lado do cliente é uma opção perfeitamente válida.
Jonathan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.