ASP.NET MVC Potencjalnie niebezpieczna wartość Request.Form została wykryta przez klienta podczas korzystania z niestandardowego modelu wiążącego

96

Tutaj pojawia się błąd:

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

Jak zezwolić tylko na wybór wartości? to znaczy

[ValidateInput(false)]
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
    ValueProviderResult value2 = bindingContext.ValueProvider.GetValue("ConfirmationMessage2");
}
DW
źródło
1
Możliwy duplikat potencjalnie niebezpiecznej wartości Request.Form został wykryty przez klienta , nie ma znaczenia, czy jest to Webforms czy MVC.
Erik Philips
2
Dzięki, ale nie spojrzałeś na mój problem jako na inny
DW
Ten sam dokładny problem źródłowy, jedyną różnicą jest to, że mogą istnieć specyficzne sposoby rozwiązania MVC.
Erik Philips,
Podczas korzystania z EF, zobacz odpowiedź bizzehdee tutaj stackoverflow.com/questions/17964313/…
Petr

Odpowiedzi:

227

Masz kilka opcji.

W modelu dodaj ten atrybut do każdej właściwości, której potrzebujesz, aby zezwolić na HTML - najlepszy wybór

using System.Web.Mvc;

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

W akcji kontrolera dodaj ten atrybut, aby zezwolić na cały kod HTML

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

Brute force w web.config - zdecydowanie nie zalecane

W pliku web.config, w obrębie tagów, wstaw element httpRuntime z atrybutem requestValidationMode = "2.0". Dodaj również atrybut validateRequest = "false" w elemencie pages.

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

Więcej informacji: http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

Powyższe działa w przypadku użycia domyślnego segregatora modelu.

Niestandardowy modelBinder

Wygląda na to, że wywołanie bindingContext.ValueProvider.GetValue () w powyższym kodzie zawsze sprawdza poprawność danych, niezależnie od atrybutów. Przeglądanie źródeł ASP.NET MVC ujawnia, że ​​DefaultModelBinder najpierw sprawdza, czy weryfikacja żądania jest wymagana, a następnie wywołuje metodę bindingContext.UnvalidatedValueProvider.GetValue () z parametrem wskazującym, czy walidacja jest wymagana, czy nie.

Niestety nie możemy użyć żadnego z kodu frameworka, ponieważ jest on zapieczętowany, prywatny lub cokolwiek innego, aby chronić nieświadomych programistów przed robieniem niebezpiecznych rzeczy, ale nie jest zbyt trudne stworzenie działającego spoiwa modelu niestandardowego, który respektuje atrybuty AllowHtml i 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...
        }
    }
}

Drugi wymagany element to sposób na odzyskanie niepotwierdzonej wartości. W tym przykładzie używamy metody rozszerzającej dla klasy 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);
    }
}

Więcej informacji na ten temat na http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/

ericdc
źródło
mam to na kontrolerze [HttpPost, ValidateInput (false)] i nadal otrzymuję błąd
DW
Zobacz moją poprawioną odpowiedź, aby obejść ten problem podczas korzystania z niestandardowego segregatora
ericdc
Dzięki, ale nie podoba mu się ta linia bindingContext.GetValueFromValueProvider
DW
GetValueFromValueProvider musi znajdować się w publicznej klasie statycznej. Sprawdź powyższe zmiany.
ericdc
Ta, valueProviderResult reutrns null tho? var valueProviderResult = bindingContext.GetValueFromValueProvider (shouldPerformRequestValidation);
DW
31

Próbować:

HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")
DW
źródło
Kiedy próbuję tego, pojawia się wyjątek, który mówi: Element członkowski nieodwołalny „System.web.HttpRequestBase.Unvalidated” nie może być używany jako metoda. Czy to się zmieniło?
Stack0verflow
7
Druga linia naprawdę powinna brzmiećvar re = request.Unvalidated.Form["ConfirmationMessage"];
Stack0verflow
5

Rozwijając na odpowiedź od @DW moim Edycja kontrolera, w iteracji nad wartościami formularza, musiałem zastąpić wszystkie wystąpienia Request.Params.AllKeysz Request.Unvalidated.Form.AllKeysi wszystkie instancje Request[key]z Request.Unvalidated.Form[key].

To było jedyne rozwiązanie, które działało dla mnie.

Mike Godin
źródło
0

Jak napisał Mike Godin, nawet jeśli ustawisz atrybut [ValidateInput (false)], musisz użyć Request.Unvalidated.Form zamiast Request.Form To zadziałało dla mnie z ASP.NET MVC 5

Ryozzo
źródło
1
W rzeczywistości była to przydatna rada, ponieważ dostęp do danych z kontrolera podstawowego (tj. Do celów dziennika lub debugowania) każdy dostęp do Request.Form zgłasza wyjątek, nawet jeśli model ma ten atrybut.
nsimeonov
-4

Oto kroki, aby zakodować na poziomie klienta i zdekodować na poziomie serwera:

  1. Opublikuj formularz za pomocą metody przesyłania jquery.

  2. W jQuery kliknij pole kodowania metody zdarzenia, które chcesz wysłać na serwer. Przykład:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
    
  3. Na poziomie kontrolera dostęp do wszystkich wartości id formularza za pomocą

    HttpUtility.UrlDecode(Request["fieldid"])
    

Przykładowy przykład:

  • Poziom kontrolera:

    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));
    }
    
  • Poziom klienta:

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

W funkcji gotowości dokumentu:

$(function () {     
  $("#btnsearch").click(function () {  
    $("#search-text").val(encodeURIComponent($("#search-text").val()));
    $("#search-form").submit();
  });
});
Prakash Rajendran
źródło
4
JQuery i technologia po stronie klienta nie mają nic wspólnego z MVC, walidacja odbywa się po stronie serwera z frameworkiem MVC. To nie jest prawidłowa odpowiedź
diegosasw
2
Biorąc pod uwagę, że Microsoft dosłownie ignoruje atrybut AllowHtml i biorąc pod uwagę, że jedynym działającym rozwiązaniem po stronie serwera jest zastąpienie funkcjonalności domyślnego spinacza modelu, argumentowałbym, że kodowanie po stronie klienta jest całkowicie poprawną opcją.
Jonathan