ASP.NET MVC 2 Beta 2更新の一部として、JSONGETリクエストはデフォルトで許可されていません。コントローラからJsonRequestBehavior
オブジェクトを返す前に、JsonResult
フィールドをJsonRequestBehavior.AllowGet
に設定する必要があるようです。
public JsonResult IsEmailValid(...)
{
JsonResult result = new JsonResult();
result.Data = ..... ;
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}
この背後にある理由は何ですか? JSON GETを使用してリモート検証を試みている場合、代わりに別の手法を使用する必要がありますか?
DenyGetのデフォルトの理由は [〜#〜] msdn [〜#〜] にあり、詳細については Phil Haackのブログ へのリンクがあります。クロスサイトスクリプティングの脆弱性のようです。
HTTP GETは、ASP.NETのクロスサイトリクエストフォージェリ(CSRF/XSRF)保護の一部としてデフォルトで無効になっています。 WebサービスがGETリクエストを受け入れる場合、サードパーティのサイトが<script />
タグを介してリクエストを行い、JavaScriptセッターを変更することでレスポンスを収集する可能性があります。
ただし、GETリクエストを無効にするだけでは、CSRF攻撃を防ぐのに十分ではなく、上記の種類の攻撃からサービスを保護する唯一の方法でもないことに注意してください。さまざまな攻撃ベクトルの適切な分析とそれらからの保護方法については、 クロスサイトリクエストフォージェリに対する堅牢な防御 を参照してください。
MVCWebサイトをVisualStudio2008からVisualStudio2010に移行したときにも問題が発生しました。
メインのaspxは以下のとおりです。これには、ViewData ["Categories"]をSelectListコレクションで埋めるためにCategoryControllerを呼び出すViewDataがあります。サブカテゴリコントローラーを呼び出して、2番目のコンボをjavascriptで埋めるスクリプトもあります。これで、この2番目のコントローラーに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); }
}
これが彼らがそのデフォルトを変更することを選んだ理由であるかどうかはわかりませんが、これが私の経験です:
一部のブラウザはGETを見ると、結果をキャッシュできると考えています。 AJAXは通常、サーバーから最新の情報を取得するための小さなリクエストに使用されるため、これらの結果をキャッシュすると、通常、予期しない動作が発生します。特定の入力が毎回同じ結果を返すことがわかっている場合(たとえば、「password」をパスワードとして使用することはできません)、GETは問題なく、ブラウザのキャッシュによって実際にパフォーマンスが向上する可能性があります。誰かが同じ入力を複数回検証しようとします。一方、サーバー側のデータの現在の状態に応じて異なる回答が予想される場合( "myfavoriteusername"は2分前に利用可能だった可能性がありますが、それ以降に取得されています)、POST最初の応答がまだ正しいとブラウザに思わせないようにするため。