サーチ…


前書き

偽造防止トークンを使用すると、サイト間の要求偽造からアプリケーションを保護することができます。この機能を使用するには、フォームから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



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow