Dlaczego potrzebny jest JsonRequestBehavior?

384

Dlaczego jest Json Request Behaviorpotrzebny

Jeśli chcę ograniczyć HttpGetżądania do mojej akcji, mogę ozdobić akcję [HttpPost]atrybutem

Przykład:

[HttpPost]
public JsonResult Foo()
{
    return Json("Secrets");
}

// Instead of:
public JsonResult Foo()
{
    return Json("Secrets", JsonRequestBehavior.AllowGet);
}

Dlaczego nie [HttpPost]wystarcza?
Dlaczego struktura „wkurza” nas za to, JsonRequestBehavior.AllowGetco JsonResultmamy. Jeśli chcę odmówić otrzymania żądań, dodam HttpPostatrybut.

gdoron wspiera Monikę
źródło
Bardzo podobny do stackoverflow.com/questions/1625671/… (chociaż znalazłem to, szukając własnego pytania :))
Jedidja
Ponieważ GET ma być idempotentny, podczas gdy POST nie. Dokonując GET -> POST, zmieniasz semantykę interfejsu.
Rism
19
Ponieważ twój kod wyglądałby zbyt czysto, gdybyś nie musiał wszędzie dodawać kruchych argumentów.
John Shedletsky

Odpowiedzi:

276

MVC domyślnie DenyGetchroni Cię przed bardzo szczególnym atakiem obejmującym żądania JSON w celu zwiększenia prawdopodobieństwa, że ​​implikacje zezwolenia na HTTP GETekspozycję zostaną rozważone przed zezwoleniem na ich wystąpienie.

W przeciwieństwie do tego, kiedy może być już za późno.

Uwaga: jeśli metoda działania nie zwraca wrażliwych danych, zezwolenie na pobranie powinno być bezpieczne.

Dalsza lektura z mojej książki Wrox ASP.NET MVC3

Domyślnie środowisko ASP.NET MVC nie pozwala na odpowiedź na żądanie HTTP GET z ładunkiem JSON. Jeśli musisz wysłać JSON w odpowiedzi na GET, musisz jawnie zezwolić na zachowanie, używając JsonRequestBehavior.AllowGet jako drugiego parametru do metody Json. Istnieje jednak szansa, że ​​złośliwy użytkownik może uzyskać dostęp do ładunku JSON w procesie znanym jako porwanie JSON. Nie chcesz zwracać poufnych informacji za pomocą JSON w żądaniu GET. Aby uzyskać więcej informacji, zobacz post Phila na http://haacked.com/archive/2009/06/24/json-hijacking.aspx/ lub ten post SO.

Haack, Phil (2011). Profesjonalny ASP.NET MVC 3 (programator Wrox do programisty) (lokalizacje Kindle 6014-6020). Wrox. Wersja Kindle.

Powiązane pytanie StackOverflow

W przypadku większości ostatnio używanych przeglądarek (począwszy od Firefox 21, Chrome 27 lub IE 10) nie jest to już luka w zabezpieczeniach.

Danludwig
źródło
20
Pozostaje jednak pytanie: dlaczego [HttpPost] nie jest wystarczający?
gdoron wspiera Monikę
4
Myślę, że to wystarczy. Potrzebujesz AllowGet tylko wtedy, gdy chcesz zezwolić na przesyłanie danych w wyniku HttpGet. DenyGet jest ustawieniem domyślnym, jeśli wywołujesz Json (dane) z 1 parametrem.
danludwig
11
To jest moje pytanie. Dlaczego framework „wkurza” nas przy JsonRequestBehavior.AllowGetkażdym JsonResult, który mam. Jeśli chcę odmówić otrzymania żądania, dodam HttpPostatrybut.
gdoron wspiera Monikę
35
Myślę, że dzieje się tak, ponieważ niewiele osób zdaje sobie sprawę z tej niejasnej luki. Mówisz, że jeśli chcesz odrzucić prośbę, zrobisz to za pomocą [HttpPost]. Jednak autorzy MVC zapewniają natychmiastową ochronę przed tego rodzaju atakami. Ponieważ musisz podjąć wysiłek, aby dodać drugi argument, powinieneś poświęcić ten czas na zastanowienie się, jakie dane ujawniasz i jak wrażliwe.
danludwig
11
Więc teraz zaśmiecamy nasz interfejs API i wprowadzamy zamieszanie czasownika do interfejsów „RESTful”, aby obejść potencjalną lukę spowodowaną przez KLIENTA? To wydaje się okropne ... ale doceniam dyskusję.
Norman H
59

Aby ci to ułatwić, możesz także utworzyć atrybut filtru akcji

public class AllowJsonGetAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var jsonResult = filterContext.Result as JsonResult;

        if (jsonResult == null)
            throw new ArgumentException("Action does not return a JsonResult, 
                                                   attribute AllowJsonGet is not allowed");

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;            

        base.OnResultExecuting(filterContext);
    }
}

i wykorzystaj go w swojej akcji

[AllowJsonGet]
public JsonResult MyAjaxAction()
{
    return Json("this is my test");
}
Arjen de Mooij
źródło
4
Dodatkowo, możesz ustawić to jako domyślny filtr w RegisterGlobalFilters: filter.Add (new AllowJsonGetAttribute ()). Ale musisz usunąć wyjątek, ponieważ filtr zostanie zastosowany do wszystkich metod akcji.
Vortex852456
8

Domyślnie Jsonresult „Deny get”

Załóżmy, że mamy metodę jak poniżej

  [HttpPost]
 public JsonResult amc(){}

Domyślnie jest to „Deny Get”.

W poniższej metodzie

public JsonResult amc(){}

Kiedy musisz zezwolić lub użyć get, musimy użyć JsonRequestBehavior.AllowGet.

public JsonResult amc()
{
 return Json(new Modle.JsonResponseData { Status = flag, Message = msg, Html = html }, JsonRequestBehavior.AllowGet);
}
Deepakmahajan
źródło
5

Ulepszając nieco odpowiedź @Arjena de Mooij, dostosowując AllowJsonGetAttribute do kontrolerów mvc (nie tylko poszczególnych metod akcji):

using System.Web.Mvc;
public sealed class AllowJsonGetAttribute : ActionFilterAttribute, IActionFilter
{
    void IActionFilter.OnActionExecuted(ActionExecutedContext context)
    {
        var jsonResult = context.Result as JsonResult;
        if (jsonResult == null) return;

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var jsonResult = filterContext.Result as JsonResult;
        if (jsonResult == null) return;

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
        base.OnResultExecuting(filterContext);
    }
}
XDS
źródło
2

Nie potrzebujesz tego.

Jeśli twoje działanie ma ten HttpPostatrybut, nie musisz przejmować się ustawieniem JsonRequestBehaviori użyj przeciążenia bez niego. Istnieje przeciążenie dla każdej metody bez JsonRequestBehaviorwyliczenia. Tutaj są:

Bez JsonRequestBehavior

protected internal JsonResult Json(object data);
protected internal JsonResult Json(object data, string contentType);
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding);

Z JsonRequestBehavior

protected internal JsonResult Json(object data, JsonRequestBehavior behavior);
protected internal JsonResult Json(object data, string contentType, 
                                   JsonRequestBehavior behavior);
protected internal virtual JsonResult Json(object data, string contentType, 
    Encoding contentEncoding, JsonRequestBehavior behavior);
Kodowanie Yoshi
źródło