2009-10-26 3 views
32

Dans le cadre de la mise à jour ASP.NET MVC 2 Beta 2, les requêtes JSON GET ne sont pas autorisées par défaut. Il semble que vous devez définir le champ JsonRequestBehavior sur JsonRequestBehavior.AllowGet avant de renvoyer un objet JsonResult à partir de votre contrôleur.Pourquoi les requêtes GET retournent-elles JSON par défaut?

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

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

    return result; 
} 

Quel est le raisonnement derrière cela? Si j'utilise JSON GET pour essayer de faire une validation à distance, devrais-je utiliser une technique différente?

+2

est une propriété "JsonRequestBehavior" ont été ajoutés que dans MVC2. Becoz J'ai essayé de chercher ceci sur mvc 1.0 et je n'ai pas pu le découvrir. – Santhosh

+0

Oui, il a été ajouté en v2. Au moins, les docs 1.0 ici (http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult_members.aspx) ne le listent pas. – Jedidja

+0

thnks pour l'info. – Santhosh

Répondre

22

La raison de la valeur par défaut de DenyGet est MSDN avec un lien vers Phil Haack's blog pour plus de détails. Ressemble à une vulnérabilité de script Cross-Site.

+0

donc si je JsonRequestBehavior.AllowGet ...cette vulnérabilité continuera-t-elle à exister ou produira-t-elle une protection ou quoi? Si je dois retourner des données JSON alors je retournerais des données Json sans Explicit me répéter ??? !!!! –

+1

@jalchr: en utilisant AllowGet la vulnérabilité existera toujours, vous dites simplement au framework que vous ne vous en souciez pas (c'est-à-dire que vous êtes OK, car vous n'envoyez pas de données sensibles) –

+0

c'est une vulnérabilité CSRF, pas Cross -Site scripting! – roo2

2

Je ne sais pas si cela est la raison pour laquelle ils ont choisi de changer cette valeur par défaut, mais voici mon expérience:

Lorsque certains navigateurs voient un GET, ils pensent qu'ils peuvent mettre en cache le résultat. Comme AJAX est généralement utilisé pour les petites requêtes afin d'obtenir les informations les plus récentes du serveur, la mise en cache de ces résultats finit généralement par provoquer un comportement inattendu. Si vous savez qu'une entrée donnée retournera le même résultat à chaque fois (par exemple, "mot de passe" ne peut pas être utilisé comme mot de passe, peu importe quand vous me le demanderez), alors un GET est parfait, et la mise en cache du navigateur peut améliorer les performances. quelqu'un essaie de valider la même entrée plusieurs fois. Si, par contre, vous attendez une réponse différente en fonction de l'état actuel des données côté serveur ("myfavoriteusername" peut être disponible il y a 2 minutes, mais il a été pris depuis), vous devez utiliser POST pour éviter d'avoir le navigateur pense que la première réponse est toujours la bonne.

+0

Idée très intéressante ... avez-vous des liens vers quels navigateurs pourraient essayer de mettre en cache un résultat GET et dans quelles circonstances? – Jedidja

+1

L'exemple le plus répandu est Internet Explorer (http://greenash.net.au/posts/thoughts/an-ie-ajax-gotcha-page-caching), mais il ne s'agit pas tant de savoir si les navigateurs le font fait que la spécification HTTP dit spécifiquement que les données récupérées avec une requête GET peuvent être mises en cache. Le framework AJAX d'ASP.NET peut définir des en-têtes pour indiquer au navigateur que le contenu ne doit pas être mis en cache, donc cela n'a peut-être rien à voir avec ce problème particulier. J'ai rencontré ce problème lorsque j'écrivais ma propre paire javascript et servlet pour communiquer via AJAX. – StriplingWarrior

+0

J'ai déjà rencontré plusieurs fois le problème de la mise en cache et l'utilisation de POST (même en ne tenant pas compte des problèmes de sécurité) est définitivement la solution. – Jedidja

8

HTTP GET est désactivé par défaut dans le cadre des protections CSRF/XSRF (Cross-Site Request Forgery) d'ASP.NET. Si vos services Web acceptent les requêtes GET, ils peuvent être vulnérables aux sites tiers en effectuant des requêtes via les tags <script /> et en récupérant potentiellement la réponse en modifiant les paramètres JavaScript. Il est à noter cependant que la désactivation des requêtes GET n'est pas suffisante pour empêcher les attaques CSRF, et qu'elle n'est pas le seul moyen de protéger votre service contre le type d'attaque décrit ci-dessus. Voir Robust Defenses for Cross-Site Request Forgery pour une bonne analyse des différents vecteurs d'attaque et comment les protéger.

3

J'ai aussi eu votre problème quand je migré mon site MVC à partir de Visual Studio 2008 à Visual Studio 2010.

Le principal ASPX est ci-dessous, il a un ViewData qui appelle un contrôleur de catégorie afin de remplir ViewData [ "Catégories"] avec la collection SelectList. Il y a aussi un script pour appeler un contrôleur de sous-catégorie pour remplir le second combo avec javascript. Maintenant, j'ai été capable de le réparer en ajoutant l'attribut AlloGet sur ce second contrôleur.

est ici le ASPX et 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" /> 
<%}%>     

ici est mon contrôleur pour les sous-catégories

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 pour l'exemple de code. Merci. – Rap

Questions connexes