asp.net-mvc
Html.AntiForgeryToken
サーチ…
前書き
偽造防止トークンを使用すると、サイト間の要求偽造からアプリケーションを保護することができます。この機能を使用するには、フォームからAntiForgeryTokenメソッドを呼び出し、保護するアクションメソッドにValidateAntiForgeryTokenAttribute属性を追加します。
フォームの送信時に検証される隠しフォームフィールド(偽造防止トークン)を生成します。
構文
- @ Html.AntiForgeryToken()
備考
CSRFトークン( __RequestVerificationToken
)を使用してajaxリクエストを送信する場合、コンテンツタイプがapplication/json
設定されていないことを確認してください。 jQueryを使用している場合、コンテンツタイプはapplication/x-www-form-urlencoded
に自動的に設定され、ASP.NET MVCによって認識されます。
あぶない
この値を設定するときは注意が必要です。これを不適切に使用すると、アプリケーションのセキュリティ上の脆弱性を開くことができます。
基本的な使用法
@Html.AntiForgeryToken()
ヘルパーメソッドは、 サイト間要求偽造 (またはCSRF)攻撃から保護します。
これは、既存のフォームの中のHtml.AntiForgeryToken()
ヘルパーを使用し、対応するコントローラアクションを[ValidateAntiForgeryToken]
属性で飾ることによって使用できます。
かみそり(YourView.cshtml)
@using (Html.BeginForm("Manage", "Account")) {
@Html.AntiForgeryToken()
<!-- ... -->
}
または
<form>
@Html.AntiForgeryToken()
<!-- ... -->
</form>
コントローラ(YourController.cs)
ターゲットアクションメソッド:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult ActionMethod(ModelObject model)
{
// ...
}
IDヒューリスティックチェックを無効にする
多くの場合、例外が表示されます
Anti forgery token is meant for user "" but the current user is "username"
これは、偽造トークンが現在ログインしているユーザーにもリンクされているためです。このエラーは、ユーザーがログインしてもトークンがサイトの匿名ユーザーにリンクされている場合に表示されます。
この動作を修正するにはいくつかの方法がありますが、CSRFトークンをユーザーのログイン状態にリンクさせたくない場合は、この機能を無効にすることができます。
この行をGlobal.asax
ファイルまたは同様のアプリケーション起動ロジックに入れます。
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
すべての投稿の検証
CSRFによって引き起こされる脆弱性のため、一般的には、HttpPostsのすべてのHttpPostでAntiForgeryTokenをチェックするのがよい習慣であると考えられます(ポストに関するいくつかの技術的問題、別の認証メカニズムおよび/または投稿はdbやファイルに保存するなどの状態を変更しません)。あなたが特別な "ignore"属性で装飾されていない限り、すべてのHttpPostを自動的にチェックする特殊なGlobalActionFilterを追加することができます。
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
bool skipCheck = filterContext.ActionDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true);
if (skipCheck)
return;
// Ajax POSTs and normal form posts have to be treated differently when it comes
// to validating the AntiForgeryToken
if (request.IsAjaxRequest())
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
}
/// <summary>
/// this should ONLY be used on POSTS that DO NOT MUTATE STATE
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class DontCheckForAntiForgeryTokenAttribute : Attribute { }
すべてのリクエストでチェックされるようにするには、グローバルアクションフィルタに追加してください
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//...
filters.Add(new ValidateAntiForgeryTokenOnAllPosts());
//...
}
}
事前使用:すべてのPOSTに対してデフォルトのAntiforgeryフィルターを適用する
POST
リクエストごとにAntiforgery attribute
を適用するのを忘れるかもしれないので、デフォルトでそれを作るべきです。このサンプルは、 Antiforgery filter
が常にPOST
リクエストごとに適用されることを確認します。
まず、新しいAntiForgeryTokenFilter
フィルタを作成します。
//This will add ValidateAntiForgeryToken Attribute to all HttpPost action methods
public class AntiForgeryTokenFilter : IFilterProvider
{
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
List<Filter> result = new List<Filter>();
string incomingVerb = controllerContext.HttpContext.Request.HttpMethod;
if (String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase))
{
result.Add(new Filter(new ValidateAntiForgeryTokenAttribute(), FilterScope.Global, null));
}
return result;
}
}
このカスタムフィルタをMVC、Application_Startに登録します。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//Cactch generic error
filters.Add(new HandleErrorAttribute());
//Anti forgery token hack for every post request
FilterProviders.Providers.Add(new AntiForgeryTokenFilter());
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
したがって、すべてのPOST
リクエストはAntiforgery属性を使用してデフォルトで保護されるため、各POSTメソッドに[ValidateAntiForgeryToken]
属性を持たせる必要はなくなりました。
Jquery AjaxリクエストでAntiForgeryTokenを使用する
最初にフォームを作成する
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
}
アクションメソッド
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Test(FormViewModel formData)
{
// ...
}
スクリプト
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
var formData = new FormData($('form')[0]);
$.ajax({
method: "POST",
url: "/demo/test",
data: formData ,
success: function (data) {
console.log(data);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(errorThrown);
}
})
</script>
contentTypeがapplication/x-www-form-urlencoded
以外のものに設定されていないことを確認し、指定されていないJqueryがデフォルトでapplication/x-www-form-urlencoded