103 votes

ASP.NET MVC Une valeur Request.Form potentiellement dangereuse a été détectée chez le client lors de l'utilisation d'un modelbinder personnalisé

Obtenir l'erreur ici:

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

Comment puis-je autoriser uniquement une sélection de valeurs ? c'est-à-dire

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

236voto

ericdc Points 2966

Vous avez quelques options.

Sur le modèle, ajoutez cet attribut à chaque propriété pour laquelle vous souhaitez autoriser le HTML - meilleur choix

using System.Web.Mvc;

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

Sur l'action du contrôleur, ajoutez cet attribut pour autoriser tout le HTML

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

Brute force dans web.config - définitivement non recommandé

Dans le fichier web.config, à l'intérieur des balises , insérez l'élément httpRuntime avec l'attribut requestValidationMode="2.0". Ajoutez également l'attribut validateRequest="false" dans l'élément pages.

Plus d'infos : http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

Le procédé ci-dessus fonctionne pour les utilisations du modelbinder par défaut.

ModelBinder personnalisé

Il semble qu'un appel à bindingContext.ValueProvider.GetValue() dans le code ci-dessus valide toujours les données, quelles que soient les attributs. En examinant le code source de ASP.NET MVC, on découvre que DefaultModelBinder vérifie d'abord si la validation de la requête est requise, puis appelle la méthode bindingContext.UnvalidatedValueProvider.GetValue() avec un paramètre indiquant si la validation est requise ou non.

Malheureusement, nous ne pouvons pas utiliser le code du framework car il est scellé, privé ou autre pour protéger les développeurs ignorants de faire des choses dangereuses, mais il n'est pas trop difficile de créer un model binder personnalisé fonctionnel qui respecte les attributs AllowHtml et ValidateInput :

public class MyModelBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Vérifie d'abord si la validation de la requête est nécessaire
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;

        // Obtenir la valeur
        var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
        if (valueProviderResult != null)
        {
            var theValue = valueProviderResult.AttemptedValue;

            // etc...
        }
    }
}

L'autre morceau requis est une façon de récupérer une valeur non validée. Dans cet exemple, nous utilisons une méthode d'extension pour la 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);
    }
}

Plus d'infos à ce sujet sur http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/

34voto

D-W Points 1988

Essayer :

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

6voto

Mike Godin Points 303

En approfondissant la réponse de @D-W, dans mon contrôleur d'édition, en itérant sur les valeurs du formulaire, j'ai dû remplacer toutes les instances de Request.Params.AllKeys par Request.Unvalidated.Form.AllKeys et toutes les instances de Request[key] par Request.Unvalidated.Form[key].

C'était la seule solution qui a fonctionné pour moi.

0voto

Ryozzo Points 62

Comme l'a écrit Mike Godin, même si vous définissez [ValidateInput(false)] attribut, vous devez utiliser Request.Unvalidated.Form au lieu de Request.Form Cela a fonctionné pour moi avec ASP.NET MVC 5

-4voto

Voici les étapes pour encoder au niveau du client et décoder au niveau du serveur:

  1. Envoyez le formulaire en utilisant la méthode de soumission jquery.

  2. Dans la méthode de l'événement de clic sur le bouton jquery, encodez le champ que vous souhaitez envoyer au serveur. Exemple:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
  3. Au niveau du contrôleur, accédez à toutes les valeurs d'identifiant de formulaire en utilisant

    HttpUtility.UrlDecode(Request["fieldid"])

Exemple d'illustration:

  • Au niveau du contrôleur:

    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));
    }
  • Au niveau du client:

    <% using (Html.BeginForm("Name", "App", FormMethod.Post, new { id = "search-form" }))
    { %>
    
    App, (Pour Qui) Nom, ou BEMSID: 
    <%= Html.TextBox("searchid", null, new {value=searchText, id = "search-text", placeholder = "Entrer une application, un nom, ou un BEMSID" })%>
    
    <% } %>

Dans la fonction Document Ready:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X