2009-10-26 12 views
32

W ramach aktualizacji programu ASP.NET MVC 2 Beta 2 żądania JSON GET są domyślnie niedozwolone. Wygląda na to, że musisz ustawić pole JsonRequestBehavior na JsonRequestBehavior.AllowGet przed zwróceniem obiektu JsonResult ze swojego kontrolera.Dlaczego żądania GET zwracają domyślnie JSON?

public JsonResult IsEmailValid(...) 
{ 
    JsonResult result = new JsonResult(); 

    result.Data = ..... ; 
    result.JsonRequestBehavior = JsonRequestBehavior.AllowGet; 

    return result; 
} 

Jaki jest tego powód? Jeśli używam JSON GET, aby spróbować przeprowadzić zdalną weryfikację, czy powinienem zamiast tego używać innej techniki?

+2

Czy "JsonRequestBehavior" własność zostały dodane tylko w mvc2. Becoz Próbowałem przeszukać to na mvc 1.0 i nie mogłem się dowiedzieć. – Santhosh

+0

Tak, została dodana w wersji 2. Przynajmniej 1.0 dokumenty tutaj (http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult_members.aspx) nie wyświetlają tego. – Jedidja

+0

thnks dla informacji. – Santhosh

Odpowiedz

22

Powodem domyślnego ustawienia DenyGet jest MSDN z łączem do Phil Haack's blog w celu uzyskania dalszych szczegółów. Wygląda na podatność na ataki typu Cross-Site Scripting.

+0

, więc jeśli JsonRequestBehavior.AllowGet ...czy ta luka w zabezpieczeniach będzie nadal istnieć, czy też zapewni jakąś ochronę? Jeśli potrzebuję zwrócić dane Json, to zwrócę dane Json bez powtórzenia samego Explicity ??? !!!! –

+1

@jalchr: używanie narzędzia AllowGet spowoduje, że luka będzie nadal występować, po prostu przekazujesz strukturę, której nie obchodzi (tj. Masz z nią dobrze, ponieważ nie wysyłasz poufnych danych) –

+0

To jest usterka CSRF, a nie Cross Skrypty – roo2

2

Nie wiem, czy to jest powód, dla którego zdecydowaliśmy się zmienić to ustawienie domyślne, ale tutaj jest moje doświadczenie:

Kiedy niektóre przeglądarki zobaczyć GET, oni myślą, że mogą buforować wynik. Ponieważ AJAX jest zwykle używany do małych żądań, aby uzyskać najbardziej aktualne informacje z serwera, buforowanie tych wyników zwykle kończy się powodując nieoczekiwane zachowanie. Jeśli wiesz, że dane wejście zwróci za każdym razem ten sam wynik (np. "Hasło" nie może być użyte jako hasło, bez względu na to, kiedy mnie poprosisz), to GET jest w porządku, a buforowanie przeglądarki może faktycznie poprawić wydajność w przypadku ktoś próbuje wielokrotnie sprawdzać to samo wejście. Jeśli, z drugiej strony, oczekujesz innej odpowiedzi w zależności od bieżącego stanu danych po stronie serwera ("myfavoriteusername" może być dostępna 2 minuty temu, ale została podjęta od tego czasu), powinieneś użyć POST, aby uniknąć przeglądarka myśli, że pierwsza odpowiedź jest nadal poprawna.

+0

Bardzo ciekawy pomysł ... czy masz jakieś linki do których przeglądarek może próbować buforować wynik GET iw jakich okolicznościach? – Jedidja

+1

Najbardziej rozpowszechnionym przykładem jest Internet Explorer (http://greenash.net.au/posts/thoughts/an-ie-ajax-gotcha-page-caching), ale nie chodzi tu o to, które przeglądarki robią to, Fakt, że specyfikacja HTTP mówi konkretnie, że dane pobierane za pomocą żądania GET są buforowalne. Środowisko ASP.NET AJAX może ustawić nagłówki, aby informowały przeglądarkę, że zawartość nie powinna być buforowana, więc może nie mieć nic wspólnego z tym konkretnym problemem. Wpadłem na ten problem, kiedy pisałem swoją własną parę javascript i serwletów, aby komunikować się za pośrednictwem AJAX. – StriplingWarrior

+0

Kilka razy natknąłem się na problem z buforowaniem i używanie POST (nawet pomijając kwestie bezpieczeństwa) jest zdecydowanie drogą do zrobienia. – Jedidja

8

HTTP GET jest domyślnie wyłączony jako część zabezpieczeń stronicowania aplikacji ASP.NET Cross-Site (CSRF/XSRF). Jeśli Twoje usługi internetowe akceptują żądania GET, mogą być podatne na ataki stron trzecich, które wysyłają żądania za pomocą tagów <script /> i potencjalnie zbierają odpowiedzi, modyfikując programy ustawiające JavaScript.

Warto jednak zauważyć, że wyłączenie żądań GET nie wystarczy, aby zapobiec atakom CSRF, ani nie jest to jedyny sposób na zabezpieczenie usługi przed typem ataku opisanym powyżej. Zobacz Robust Defenses for Cross-Site Request Forgery dla dobrej analizy różnych wektorów ataku i sposobów ochrony przed nimi.

3

miałem też problemu, kiedy migracji moją stronę MVC z Visual Studio 2008 do Visual Studio 2010.

Głównym aspx jest poniżej, ma ViewData który wywołuje kategorię Controller w celu wypełnienia się ViewData [ "Kategorie"] z kolekcją SelectList. Istnieje również skrypt do wywoływania kontrolera podkategorii w celu uzupełnienia drugiego combo za pomocą javascript. Teraz udało mi się to naprawić, dodając atrybut AlloGet do tego drugiego kontrolera.

Oto aspx i javascript

<head> 
<script type="text/javascript" src="../../Scripts/jquery-1.4.1.min.js"></script> 
<script type="text/javascript"> 
$(document).ready(function() { 
$("#CategoryId").change(function() { 

    var categoryId = $(this)[0].value; 

    $("#ctl00_MainContent_SubcategoryId").empty(); 
    $("#ctl00_MainContent_SubcategoryId").append("<option value=''>-- select a category --</option>"); 
    var url = "/Subcategory/Subcategories/" + categoryId; 

    $.getJSON(url, { "selectedItem": "" }, function (data) { 
     $.each(data, function (index, optionData) { 
      $("#ctl00_MainContent_SubcategoryId").append("<option value='" + optionData.SubcategoryId + "'>" + optionData.SubcategoryName + "</option>"); 
     }); 
     //feed our hidden html field 
     var selected = $("#chosenSubcategory") ? $("#chosenSubcategory").val() : ''; 
     $("#ctl00_MainContent_SubcategoryId").val(selected); 

    }); 

}).change(); 
}); 
</script> 
<body> 
<% using (Html.BeginForm()) {%> 
<label for="CategoryId">Category:</label></td> 
<%= Html.DropDownList("CategoryId", (SelectList)ViewData["Categories"], "--categories--") %> 
<%= Html.ValidationMessage("category","*") %> 
<br/> 
<label class="formlabel" for="SubcategoryId">Subcategory:</label><div id="subcategoryDiv"></div> 
<%=Html.Hidden("chosenSubcategory", TempData["subcategory"])%> 
<select id="SubcategoryId" runat="server"> 
</select><%= Html.ValidationMessage("subcategory", "*")%> 
<input type="submit" value="Save" /> 
<%}%>     

oto mój kontroler dla podkategorii

public class SubcategoryController : Controller 
{ 
    private MyEntities db = new MyEntities(); 

    public int SubcategoryId { get; set; } 
    public int SubcategoryName { get; set; } 
    public JsonResult Subcategories(int? categoryId) 
    { 
     try 
     { 
      if (!categoryId.HasValue) 
       categoryId = Convert.ToInt32(RouteData.Values["id"]); 
      var subcategories = (from c in db.Subcategories.Include("Categories") 
           where c.Categories.CategoryId == categoryId && c.Active && !c.Deleted 
            && c.Categories.Active && !c.Categories.Deleted 
           orderby c.SubcategoryName 
           select new { SubcategoryId = c.SubcategoryId, SubcategoryName = c.SubcategoryName } 
      ); 
      //just added the allow get attribute 
      return this.Json(subcategories, JsonRequestBehavior.AllowGet); 
     } 
     catch { return this.Json(null); } 

    } 
+0

+1 dla próbki kodu. Dzięki. – Rap