Почему запросы GET, возвращающие JSON, по умолчанию запрещены? - PullRequest
33 голосов
/ 26 октября 2009

В рамках обновления ASP.NET MVC 2 Beta 2 запросы JSON GET по умолчанию запрещены. Похоже, вам нужно установить для поля JsonRequestBehavior значение JsonRequestBehavior.AllowGet, прежде чем возвращать объект JsonResult из вашего контроллера.

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

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

    return result;
}

В чем причина этого? Если я использую JSON GET, чтобы попытаться выполнить некоторую удаленную проверку, следует ли мне использовать другую технику вместо этого?

Ответы [ 4 ]

23 голосов
/ 26 октября 2009

Причиной по умолчанию DenyGet является MSDN со ссылкой на блог Фила Хаака для получения дополнительной информации. Похоже, уязвимость межсайтового скриптинга.

8 голосов
/ 26 октября 2009

HTTP GET отключен по умолчанию как часть защиты ASP.NET от подделки межсайтовых запросов (CSRF / XSRF). Если ваши веб-службы принимают запросы GET, то они могут быть уязвимы для сторонних сайтов, которые отправляют запросы с помощью тегов <script /> и потенциально собирают ответ путем изменения настроек JavaScript.

Стоит отметить, однако, что отключение запросов GET недостаточно для предотвращения CSRF-атак и не является единственным способом защиты вашей службы от атак, описанных выше. См. Надежная защита для подделки межсайтовых запросов для хорошего анализа различных векторов атак и способов защиты от них.

3 голосов
/ 17 мая 2010

У меня также была ваша проблема при переносе моего веб-сайта MVC из Visual Studio 2008 в Visual Studio 2010.

Основной aspx ниже, у него есть ViewData, который вызывает контроллер категории, чтобы заполнить ViewData ["Categories"] коллекцией SelectList. Также есть скрипт для вызова контроллера подкатегории, чтобы заполнить второе комбо с помощью javascript. Теперь я смог исправить это, добавив атрибут AlloGet на этот второй контроллер.

Вот aspx и 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" />
<%}%>                

вот мой контроллер для подкатегорий

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

    }
2 голосов
/ 26 октября 2009

Я не знаю, по этой ли причине они решили изменить значение по умолчанию, но вот мой опыт:

Когда некоторые браузеры видят GET, они думают, что могут кэшировать результат. Поскольку AJAX обычно используется для небольших запросов для получения самой последней информации с сервера, кэширование этих результатов обычно приводит к непредвиденному поведению. Если вы знаете, что данный ввод будет возвращать один и тот же результат каждый раз (например, «пароль» не может использоваться в качестве пароля, независимо от того, когда вы меня спрашиваете), то GET - это нормально, и кеширование в браузере может на самом деле улучшить производительность в случае кто-то пытается проверить один и тот же ввод несколько раз. Если, с другой стороны, вы ожидаете другого ответа в зависимости от текущего состояния данных на стороне сервера («myfavoriteusername» могло быть доступно 2 минуты назад, но с тех пор оно было принято), вам следует использовать POST, чтобы избежать браузер думает, что первый ответ по-прежнему правильный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...