28 votes

Pourquoi les requêtes GET retournant du JSON ne sont-elles pas autorisées par défaut ?

Dans le cadre de la mise à jour d'ASP.NET MVC 2 Beta 2, les requêtes JSON GET ne sont pas autorisées par défaut. Il semble que vous deviez définir l'option JsonRequestBehavior pour JsonRequestBehavior.AllowGet avant de renvoyer un JsonResult de votre contrôleur.

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 d'effectuer une validation à distance, devrais-je plutôt utiliser une autre technique ?

18voto

Chris Shaffer Points 18066

La raison du défaut DenyGet est sur MSDN avec un lien vers Le blog de Phil Haack pour plus de détails. Cela ressemble à une vulnérabilité de scripting Cross-Site.

7voto

Annabelle Points 4476

La fonction GET HTTP est désactivée par défaut dans le cadre des protections contre la falsification des requêtes intersites (CSRF/XSRF) d'ASP.NET. Si vos services web acceptent les requêtes GET, ils peuvent être vulnérables aux sites tiers qui effectuent des requêtes par l'intermédiaire de la fonction <script /> et de récolter potentiellement la réponse en modifiant les paramètres JavaScript.

Il convient toutefois de noter que la désactivation des requêtes GET ne suffit pas à empêcher les attaques CSRF et ne constitue pas non plus le seul moyen de protéger votre service contre le type d'attaque décrit ci-dessus. Voir Défenses robustes contre la falsification des requêtes intersites pour une bonne analyse des différents vecteurs d'attaque et de la manière de s'en protéger.

2voto

StriplingWarrior Points 56276

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

Lorsque certains navigateurs voient un GET, ils pensent qu'ils peuvent mettre le résultat en cache. Étant donné qu'AJAX est généralement utilisé pour de petites requêtes visant à 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 renverra le même résultat à chaque fois (par exemple, "mot de passe" ne peut pas être utilisé comme mot de passe, quel que soit le moment où vous me le demandez), alors un GET est parfait, et la mise en cache du navigateur peut en fait améliorer les performances au cas où quelqu'un tenterait 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" était peut-être disponible il y a 2 minutes, mais il a été pris depuis), vous devez utiliser POST pour éviter que le navigateur ne pense que la première réponse est toujours la bonne.

2voto

Junior Mayhé Points 5202

J'ai également rencontré votre problème lorsque j'ai migré mon site web MVC de Visual Studio 2008 à Visual Studio 2010.

L'aspx principal est ci-dessous, il a un ViewData qui appelle un Category Controller afin de remplir ViewData["Categories"] avec la collection SelectList. Il y a aussi un script qui appelle un contrôleur Subcategory pour remplir le deuxième combo avec du javascript. Maintenant, j'ai été en mesure de le fixer en ajoutant l'attribut AlloGet sur ce deuxième contrôleur.

Voici l'aspx et le 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" />
<%}%>                

voici 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); }

    }

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