ASP.NET Core で防ぐクロスサイト リクエスト フォージェリ (XSRF または CSRF) 攻撃Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core

著者: Steve SmithFiyaz Hasan、および Rick AndersonBy Steve Smith, Fiyaz Hasan, and Rick Anderson

クロスサイトリクエストフォージェリ(XSRF または CSRF とも呼ばれます)は、Web でホストされているアプリへの攻撃であり、それによって悪意のある Web アプリが、クライアントのブラウザーとそのブラウザーを信頼している Web アプリとのやり取りに影響を及ぼします。Cross-site request forgery (also known as XSRF or CSRF) is an attack against web-hosted apps whereby a malicious web app can influence the interaction between a client browser and a web app that trusts that browser. Web ブラウザーは、Web サイトへのリクエストの度にある種の認証トークンを送信しているため、攻撃が可能です。These attacks are possible because web browsers send some types of authentication tokens automatically with every request to a website. この形式の攻撃は、ワンクリック攻撃セッションライディングとしても知られています。これは、 攻撃者がユーザーの認証済みのセッションを利用するためです。This form of exploit is also known as a one-click attack or session riding because the attack takes advantage of the user's previously authenticated session.

CSRF 攻撃の例:An example of a CSRF attack:

  1. ユーザーがフォーム認証を使用して www.good-banking-site.com にサインインします。A user signs into www.good-banking-site.com using forms authentication. サーバーはユーザーを認証し、認証 Cookie を含む応答を返します。The server authenticates the user and issues a response that includes an authentication cookie. このサイトは有効な認証 Cookie を持った要求を全て信頼しているため、攻撃に対して脆弱です。The site is vulnerable to attack because it trusts any request that it receives with a valid authentication cookie.

  2. ユーザーは、悪意のあるサイトである www.bad-crook-site.com にアクセスします。The user visits a malicious site, www.bad-crook-site.com.

    悪意のあるサイトである www.bad-crook-site.com では、次のような HTML フォームが含まれているとします:The malicious site, www.bad-crook-site.com, contains an HTML form similar to the following:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="http://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw">
        <input type="hidden" name="Amount" value="1000000">
        <input type="submit" value="Click to collect your prize!">
    </form>
    

    注意として、フォームの action は脆弱性のあるサイトにポストしており、悪意のあるサイトへではありません。Notice that the form's action posts to the vulnerable site, not to the malicious site. これは、CSRF の "cross-site" の一部です。This is the "cross-site" part of CSRF.

  3. ユーザーは、[送信] ボタンを選択します。The user selects the submit button. ブラウザーが要求を行うと、自動的に、要求先のドメインである www.good-banking-site.com の認証 Cookie が含まれます。The browser makes the request and automatically includes the authentication cookie for the requested domain, www.good-banking-site.com.

  4. 要求は、ユーザーの認証コンテキストを持った状態で www.good-banking-site.com サーバー上で実行されるので、認証されたユーザーに許可されている任意のアクションを実行できます。The request runs on the www.good-banking-site.com server with the user's authentication context and can perform any action that an authenticated user is allowed to perform.

ユーザーがフォームの送信ボタンを選択するシナリオに加えて、悪意のあるサイトは以下のことを行う可能性があります。In addition to the scenario where the user selects the button to submit the form, the malicious site could:

  • 自動的にフォームの送信をするスクリプトの実行Run a script that automatically submits the form.
  • フォームの送信を AJAX 要求として送信Send the form submission as an AJAX request.
  • CSS を使用してフォームを非表示Hide the form using CSS.

これらのシナリオでは、最初に悪意のあるサイトにアクセスする以外に、ユーザーの操作や入力は必要ありません。These alternative scenarios don't require any action or input from the user other than initially visiting the malicious site.

HTTPS を使用しても CSRF 攻撃を防ぐことはできません。Using HTTPS doesn't prevent a CSRF attack. 悪意のあるサイトは、セキュアではないリクエストを送信するの同じくらい容易に https://www.good-banking-site.com/ へリクエストを送信することができます。The malicious site can send an https://www.good-banking-site.com/ request just as easily as it can send an insecure request.

GET 要求の応答のエンドポイントを標的とした攻撃もあります。その場合、イメージタグがアクションの実行によく使われます。Some attacks target endpoints that respond to GET requests, in which case an image tag can be used to perform the action. この形式の攻撃は、画像は許可するが JavaScript はブロックするフォーラムのサイトでよくあります。This form of attack is common on forum sites that permit images but block JavaScript. GETメソッドの変数やリソースの変更によって状態を変更するアプリは、悪意のある攻撃に対して脆弱です。Apps that change state on GET requests, where variables or resources are altered, are vulnerable to malicious attacks. 状態を変更する GET 要求はセキュアではありません。ベストプラクティスは、GET 要求で状態を変更しないことです。GET requests that change state are insecure. A best practice is to never change state on a GET request.

認証に Cookie を使用する Web アプリに対して、CSRF 攻撃が可能です。理由は以下です。CSRF attacks are possible against web apps that use cookies for authentication because:

  • ブラウザーは Web アプリが発行した Cookie を保存します。Browsers store cookies issued by a web app.
  • 保存された Cookie には、認証されたユーザーのセッション Cookie が含まれています。Stored cookies include session cookies for authenticated users.
  • ブラウザーは、ブラウザー内でアプリへのリクエストがどのように生成されたかにかかわらず、Web アプリの全ての要求に対しドメインに関連する全ての Cookie を送信します。Browsers send all of the cookies associated with a domain to the web app every request regardless of how the request to app was generated within the browser.

しかし、CSRF 攻撃は Cookie の悪用だけではありません。However, CSRF attacks aren't limited to exploiting cookies. 例えば、ベーシック認証やダイジェスト認証も脆弱です。For example, Basic and Digest authentication are also vulnerable. ベーシック認証やダイジェスト認証でサインインした後、ブラウザーは動的にセッション†が終了するまで自動的に資格情報を送信します。After a user signs in with Basic or Digest authentication, the browser automatically sends the credentials until the session† ends.

†ここでの セッション は、ユーザーが認証されている間のクライアントサイドのセッションを指します。†In this context, session refers to the client-side session during which the user is authenticated. サーバーサイドのセッションやASP.NET Core のセッションミドルウェアとは無関係です。It's unrelated to server-side sessions or ASP.NET Core Session Middleware.

ユーザーは、次の対策をとることで CSRF の脆弱性を防ぐことができます。Users can guard against CSRF vulnerabilities by taking precautions:

  • 使用が終わったら、Web アプリからサインオフするSign off of web apps when finished using them.
  • 定期的にブラウザーの Cookie をクリアするClear browser cookies periodically.

ただし、CSRF の脆弱性は基本的に Web アプリの問題であり、エンドユーザーの問題ではありません。However, CSRF vulnerabilities are fundamentally a problem with the web app, not the end user.

認証の基礎Authentication fundamentals

Cookie ベースの認証は一般的な認証方式です。Cookie-based authentication is a popular form of authentication. トークンベースの認証システムは、特にシングルページアプリケーション(SPA)で人気が高まっています。Token-based authentication systems are growing in popularity, especially for Single Page Applications (SPAs).

ユーザーがユーザー名とパスワードを使って認証すると、ユーザーが認証と承認ができる認証チケットを含むトークンが発行されます。When a user authenticates using their username and password, they're issued a token, containing an authentication ticket that can be used for authentication and authorization. トークンは、クライアントが生成する全てのリクエストに含まれる Cookie として保存されます。The token is stored as a cookie that accompanies every request the client makes. この Cookie の生成と検証は Cookie 認証ミドルウェアによって処理されます。Generating and validating this cookie is performed by the Cookie Authentication Middleware. ミドルウェアは、ユーザープリンシパルを暗号化した Cookie にシリアル化します。The middleware serializes a user principal into an encrypted cookie. 以降の要求では、ミドルウェアが Cookie を検証し、プリンシパルを再作成したりそのプリンシパルを HttpContextUser プロパティに割り当てます。On subsequent requests, the middleware validates the cookie, recreates the principal, and assigns the principal to the User property of HttpContext.

トークンベースの認証Token-based authentication

ユーザーが認証されると、(偽造防止トークンとは別の)トークンが発行されます。When a user is authenticated, they're issued a token (not an antiforgery token). トークンには、Claim 形式のユーザー情報や、アプリ内で保持されているユーザーの状態をアプリに紐づける参照トークンが含まれています。The token contains user information in the form of claims or a reference token that points the app to user state maintained in the app. ユーザーが認証の必要なリソースにアクセスしようとすると、ベアラートークンの形式で追加の認証ヘッダーを付与して、アプリにトークンが送信されます。When a user attempts to access a resource requiring authentication, the token is sent to the app with an additional authorization header in form of Bearer token. これによってアプリはステートレスになります。This makes the app stateless. 以降の要求では、サーバーサイドでの検証のためにトークンが渡されます。In each subsequent request, the token is passed in the request for server-side validation. このトークンは、暗号化 されていません。 エンコード されています。This token isn't encrypted; it's encoded. サーバーでは、この情報にアクセスするためにトークンがデコードされます。On the server, the token is decoded to access its information. 以降のリクエストでトークンを送信する際は、ブラウザーのローカルストレージに保存します。To send the token on subsequent requests, store the token in the browser's local storage. トークンがブラウザーのローカルストレージに保存された場合、CSRF の脆弱性の心配はありません。Don't be concerned about CSRF vulnerability if the token is stored in the browser's local storage. トークンが Cookie に保存されている場合は、CSRF の懸念があります。CSRF is a concern when the token is stored in a cookie.

1 つのドメインでホストされている複数のアプリMultiple apps hosted at one domain

共有のホスティング環境では、セッションハイジャック、ログインの CSRFやその他の攻撃に対して脆弱です。Shared hosting environments are vulnerable to session hijacking, login CSRF, and other attacks.

example1.contoso.netexample2.contoso.net は別のホストですが、 *.contoso.net ドメイン下のホストにあるため、暗黙の信頼関係があります。Although example1.contoso.net and example2.contoso.net are different hosts, there's an implicit trust relationship between hosts under the *.contoso.net domain. この暗黙の信頼関係により、潜在的に信頼できないホストに対して互いの Cookie が影響を及ぼす可能性があります(AJAX 要求を管理する同一オリジンポリシーは、HTTP の Cookie には必ずしも適用されるわけではありません)。This implicit trust relationship allows potentially untrusted hosts to affect each other's cookies (the same-origin policies that govern AJAX requests don't necessarily apply to HTTP cookies).

同じドメインでホストされているアプリ感の信頼された Cookie を悪用した攻撃は、ドメインを共有しないことで防ぐことができます。Attacks that exploit trusted cookies between apps hosted on the same domain can be prevented by not sharing domains. アプリがそれぞれ各自のドメインでホストされていれば、悪用できる信頼関係をもつ暗黙的な Cookie はありません。When each app is hosted on its own domain, there is no implicit cookie trust relationship to exploit.

ASP.NET Core の偽造防止の構成ASP.NET Core antiforgery configuration

警告

ASP.NET Core では、ASP.NET Core データ保護を使用して偽造防止の実装をします。ASP.NET Core implements antiforgery using ASP.NET Core Data Protection. データ保護のスタックは、サーバー ファームで動作するように構成する必要があります。The data protection stack must be configured to work in a server farm. 詳しくは、データ保護の構成を参照してください。See Configuring data protection for more information.

ASP.NET Core 2.0 以降では、 FormTagHelperが HTML フォームの要素に偽造防止トークンを挿入します。In ASP.NET Core 2.0 or later, the FormTagHelper injects antiforgery tokens into HTML form elements. Razor ファイルの次のマークアップには、偽造防止トークンが自動的に生成されます:The following markup in a Razor file automatically generates antiforgery tokens:

<form method="post">
    ...
</form>

同様に、 IHtmlHelper.BeginForm も GET 以外のメソッドの場合、デフォルトで偽造防止トークンを生成します。Similarly, IHtmlHelper.BeginForm generates antiforgery tokens by default if the form's method isn't GET.

HTML フォーム要素の偽造防止トークンの自動生成は、<form> タグに method="post" 属性が含まれていて、次のいずれかが当てはまる場合に生成されます:The automatic generation of antiforgery tokens for HTML form elements happens when the <form> tag contains the method="post" attribute and either of the following are true:

  • Action 属性が空(action=""The action attribute is empty (action="").
  • Action 属性が指定されていない(<form method="post">The action attribute isn't supplied (<form method="post">).

HTML フォーム要素で偽造防止トークンの自動生成を無効にすることができます:Automatic generation of antiforgery tokens for HTML form elements can be disabled:

  • asp-antiforgery属性によって偽造防止トークンを明示的に無効化する:Explicitly disable antiforgery tokens with the asp-antiforgery attribute:

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • フォーム要素で、タグヘルパーの ! opt-out symbol によって、タグヘルパーがオプトアウトされます:The form element is opted-out of Tag Helpers by using the Tag Helper ! opt-out symbol:

    <!form method="post">
        ...
    </!form>
    
  • ビューから FormTagHelper を削除します。Remove the FormTagHelper from the view. FormTagHelper は、Razor ビューに次のディレクティブを追加することで、ビューから削除できます:The FormTagHelper can be removed from a view by adding the following directive to the Razor view:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

注意

Razor ページは、自動的に XSRF/CSRF から保護されます。Razor Pages are automatically protected from XSRF/CSRF. 詳細については、XSRF/CSRF と Razor ページ 参照してください。For more information, see XSRF/CSRF and Razor Pages.

CSRF 攻撃に対する防御の最も一般的なアプローチは、Synchronizer Token Pattern(STP)を使用することです。The most common approach to defending against CSRF attacks is to use the Synchronizer Token Pattern (STP). STPは、ユーザーがフォームデータを含むページを要求したときに使用されます:STP is used when the user requests a page with form data:

  1. サーバーは、現在のユーザーの ID に関連したトークンをクライアントに送信します。The server sends a token associated with the current user's identity to the client.
  2. クライアントは、検証のためにトークンをサーバーに送り返します。The client sends back the token to the server for verification.
  3. サーバーが認証されたユーザーの ID と一致しないトークンを受け取った場合、要求は拒否されます。If the server receives a token that doesn't match the authenticated user's identity, the request is rejected.

トークンは一意で予測不可能です。The token is unique and unpredictable. トークンは、一連の要求の適切な順序付け(例えば、ページ1 – ページ2 – ページ3といった要求順の保証)を保証するためにも使用できます。The token can also be used to ensure proper sequencing of a series of requests (for example, ensuring the request sequence of: page 1 – page 2 – page 3). ASP.NET Core MVC と Razor Pages のテンプレートの全てのフォームで偽造防止トークンは生成できます。All of the forms in ASP.NET Core MVC and Razor Pages templates generate antiforgery tokens. 次の2つのビューの例で、偽造防止トークンを生成します:The following pair of view examples generate antiforgery tokens:

<form asp-controller="Manage" asp-action="ChangePassword" method="post">
    ...
</form>

@using (Html.BeginForm("ChangePassword", "Manage"))
{
    ...
}

タグヘルパーを使わず、HTML ヘルパーの@Html.AntiForgeryTokenを使って明示的に偽造防止トークンを追加します:Explicitly add an antiforgery token to a <form> element without using Tag Helpers with the HTML helper @Html.AntiForgeryToken:

<form action="/" method="post">
    @Html.AntiForgeryToken()
</form>

上の 2 つのケースでは、ASP.NET Core は次の隠しフォームフィールドを追加します:In each of the preceding cases, ASP.NET Core adds a hidden form field similar to the following:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core では、偽造防止トークンを動作するために 3 つのフィルターが含まれています:ASP.NET Core includes three filters for working with antiforgery tokens:

偽造防止のオプションAntiforgery options

Startup.ConfigureServices で、偽造防止のオプションをカスタマイズできます:Customize antiforgery options in Startup.ConfigureServices:

services.AddAntiforgery(options => 
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

CookieBuilder クラスのプロパティを使って、偽造防止の Cookie プロパティを設定できます。†Set the antiforgery Cookie properties using the properties of the CookieBuilder class.

OPTIONOption 説明Description
CookieCookie 偽造防止の Cookie の作成に使用する設定を決定します。Determines the settings used to create the antiforgery cookies.
FormFieldNameFormFieldName 偽造防止トークンをビューに表示するために偽造防止システムで使われる、隠しフォームフィールドの名前。The name of the hidden form field used by the antiforgery system to render antiforgery tokens in views.
HeaderNameHeaderName 偽造防止システムで使用されるヘッダーの名前。The name of the header used by the antiforgery system. null の場合、システムはフォームデータのみを考慮します。If null, the system considers only form data.
SuppressXFrameOptionsHeaderSuppressXFrameOptionsHeader X-Frame-Options ヘッダーの生成を抑制するかを指定します。Specifies whether to suppress generation of the X-Frame-Options header. デフォルトでは、ヘッダーは "SAMEORIGIN"の値で生成されます。By default, the header is generated with a value of "SAMEORIGIN". デフォルトは false です。Defaults to false.
services.AddAntiforgery(options => 
{
    options.CookieDomain = "contoso.com";
    options.CookieName = "X-CSRF-TOKEN-COOKIENAME";
    options.CookiePath = "Path";
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.RequireSsl = false;
    options.SuppressXFrameOptionsHeader = false;
});
OPTIONOption 説明Description
CookieCookie 偽造防止の Cookie の作成に使用する設定を決定します。Determines the settings used to create the antiforgery cookies.
CookieDomainCookieDomain Cookie のドメイン。The domain of the cookie. 既定値は null です。Defaults to null. このプロパティは廃止され、今後のバージョンで削除される予定です。This property is obsolete and will be removed in a future version. Cookie.Domain お勧めします。The recommended alternative is Cookie.Domain.
CookieNameCookieName クッキーの名前。The name of the cookie. 設定されていないシステム生成一意の名前の先頭に、 DefaultCookiePrefix ("。AspNetCore.Antiforgery。")。If not set, the system generates a unique name beginning with the DefaultCookiePrefix (".AspNetCore.Antiforgery."). このプロパティは廃止され、今後のバージョンで削除される予定です。This property is obsolete and will be removed in a future version. Cookie.Name お勧めします。The recommended alternative is Cookie.Name.
CookiePathCookiePath Cookie の設定のパス。The path set on the cookie. このプロパティは廃止され、今後のバージョンで削除される予定です。This property is obsolete and will be removed in a future version. Cookie.Path お勧めします。The recommended alternative is Cookie.Path.
FormFieldNameFormFieldName 偽造防止トークンをビューに表示するために偽造防止システムで使われる、隠しフォームフィールドの名前。The name of the hidden form field used by the antiforgery system to render antiforgery tokens in views.
HeaderNameHeaderName 偽造防止システムで使用されるヘッダーの名前。The name of the header used by the antiforgery system. null の場合、システムはフォームデータのみを考慮します。If null, the system considers only form data.
RequireSslRequireSsl 偽造防止システムで HTTPS が必要かどうかを指定します。Specifies whether HTTPS is required by the antiforgery system. 場合true、HTTPS 以外の要求は失敗します。If true, non-HTTPS requests fail. 既定値は false です。Defaults to false. このプロパティは廃止され、今後のバージョンで削除される予定です。This property is obsolete and will be removed in a future version. Cookie.SecurePolicy を設定することをお勧めします。The recommended alternative is to set Cookie.SecurePolicy.
SuppressXFrameOptionsHeaderSuppressXFrameOptionsHeader X-Frame-Options ヘッダーの生成を抑制するかを指定します。Specifies whether to suppress generation of the X-Frame-Options header. デフォルトでは、ヘッダーは "SAMEORIGIN"の値で生成されます。By default, the header is generated with a value of "SAMEORIGIN". デフォルトは false です。Defaults to false.

詳細については、CookieAuthenticationOptions を参照してください。For more information, see CookieAuthenticationOptions.

IAntiforgery 偽造防止の機能を構成するConfigure antiforgery features with IAntiforgery

IAntiforgery は偽造防止の機能を構成する API を提供します。IAntiforgery provides the API to configure antiforgery features. IAntiforgeryStartup クラスの Configure メソッドで要求されます。IAntiforgery can be requested in the Configure method of the Startup class. 次の例では、ミドルウェアを使用して、アプリのホームページから偽造防止トークンを生成し、それを Cookie として応答を送信しています(このトピックで後述する Angular のデフォルトの命名規則を使っています):The following example uses middleware from the app's home page to generate an antiforgery token and send it in the response as a cookie (using the default Angular naming convention described later in this topic):

public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (
            string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            // The request token can be sent as a JavaScript-readable cookie, 
            // and Angular uses it by default.
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

偽造防止の検証の要求Require antiforgery validation

ValidateAntiForgeryToken は、個々のアクション、コントローラー、またはグローバルに適用できるアクションフィルターです。ValidateAntiForgeryToken is an action filter that can be applied to an individual action, a controller, or globally. このフィルターが適用したアクションへの要求は、有効な偽造防止トークンが含まていなければブロックされます。Requests made to actions that have this filter applied are blocked unless the request includes a valid antiforgery token.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
    ManageMessageId? message = ManageMessageId.Error;
    var user = await GetCurrentUserAsync();

    if (user != null)
    {
        var result = 
            await _userManager.RemoveLoginAsync(
                user, account.LoginProvider, account.ProviderKey);

        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            message = ManageMessageId.RemoveLoginSuccess;
        }
    }

    return RedirectToAction(nameof(ManageLogins), new { Message = message });
}

ValidateAntiForgeryToken 属性は、HTTP GET の要求も含め、属性の付いたアクションメソッドへの要求にはトークンが必要になります。The ValidateAntiForgeryToken attribute requires a token for requests to the action methods it decorates, including HTTP GET requests. ValidateAntiForgeryToken 属性がアプリのコントローラーで適用されている場合は、IgnoreAntiforgeryToken 属性で上書きできます。If the ValidateAntiForgeryToken attribute is applied across the app's controllers, it can be overridden with the IgnoreAntiforgeryToken attribute.

注意

ASP.NET Core では、GET 要求に対して偽造防止トークンの自動的な追加はサポートしていません。ASP.NET Core doesn't support adding antiforgery tokens to GET requests automatically.

安全でない HTTP メソッドのみ偽造防止トークンを自動的に検証Automatically validate antiforgery tokens for unsafe HTTP methods only

ASP.NET Core アプリケーションでは、安全な HTTP メソッド(GET、HEAD、OPTIONS、および TRACE)に対して偽造防止トークンを生成しません。ASP.NET Core apps don't generate antiforgery tokens for safe HTTP methods (GET, HEAD, OPTIONS, and TRACE). 明示的に ValidateAntiForgeryToken 属性を適用してから IgnoreAntiforgeryToken で上書きする代わりとして、AutoValidateAntiforgeryToken 属性を使うことができます。Instead of broadly applying the ValidateAntiForgeryToken attribute and then overriding it with IgnoreAntiforgeryToken attributes, the AutoValidateAntiforgeryToken attribute can be used. この属性は、ValidateAntiForgeryToken 属性と同様に機能しますが、次の HTTP メソッドを使った要求にトークンを必要としません:This attribute works identically to the ValidateAntiForgeryToken attribute, except that it doesn't require tokens for requests made using the following HTTP methods:

  • GETGET
  • HEADHEAD
  • OPTIONOPTIONS
  • TRACETRACE

API ではないシナリオでは、AutoValidateAntiforgeryToken の使用をお薦めします。We recommend use of AutoValidateAntiforgeryToken broadly for non-API scenarios. これで POST のアクションはデフォルトで保護されます。This ensures POST actions are protected by default. 別の方法として、ValidateAntiForgeryToken が個別にアクションメソッドに適用されていない限り、デフォルトで偽造防止トークンを無効にすることもできます。The alternative is to ignore antiforgery tokens by default, unless ValidateAntiForgeryToken is applied to individual action methods. このシナリオでは、POST のアクションメソッドが誤って保護されずにアプリが CSRF 攻撃に対して脆弱のままになる可能性が高くなります。It's more likely in this scenario for a POST action method to be left unprotected by mistake, leaving the app vulnerable to CSRF attacks. すべての POST メソッドが偽造防止トークンを送信すべきです。All POSTs should send the antiforgery token.

API は、トークンの Cookie 以外の部分を送信する自動的なメカニズムはありません。APIs don't have an automatic mechanism for sending the non-cookie part of the token. その実装はクライアントのコードの実装に依存するでしょう。The implementation probably depends on the client code implementation. 以下でいくつかの例を挙げます。Some examples are shown below:

クラスレベルの例:Class-level example:

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{

グローバルの例:Global example:

services.AddMvc(options => 
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

グローバルまたはコントローラーの偽造防止属性の上書きOverride global or controller antiforgery attributes

IgnoreAntiforgeryToken フィルターを使用して、特定のアクション(またはコントローラー)の偽造防止トークンの必要性を無くすことができます。The IgnoreAntiforgeryToken filter is used to eliminate the need for an antiforgery token for a given action (or controller). 適用すると、このフィルターはハイレベル(グローバルまたはコントローラー上)で指定された ValidateAntiForgeryTokenAutoValidateAntiforgeryToken フィルターを上書きします。When applied, this filter overrides ValidateAntiForgeryToken and AutoValidateAntiforgeryToken filters specified at a higher level (globally or on a controller).

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
    {
        // no antiforgery token required
    }
}

認証後のリフレッシュトークンRefresh tokens after authentication

ユーザーの認証後、ビューまたは Razor Pages のページにリダイレクトするときにトークンを更新する必要があります。Tokens should be refreshed after the user is authenticated by redirecting the user to a view or Razor Pages page.

JavaScript、AJAX、および SPAJavaScript, AJAX, and SPAs

従来の HTML ベースのアプリでは、偽造防止トークンは隠しフォーム フィールドを使ってサーバーに渡されていました。In traditional HTML-based apps, antiforgery tokens are passed to the server using hidden form fields. 最新の JavaScript ベースや SPA では多くの要求がプログラムによって行われています。In modern JavaScript-based apps and SPAs, many requests are made programmatically. これらの AJAX 要求は、トークンを送信するための他の技術(要求ヘッダーや Cookie)を使うことがあります。These AJAX requests may use other techniques (such as request headers or cookies) to send the token.

Cookie に認証トークンを保存しサーバーの API の要求で認証するために使われるなら、CSRF は潜在的な問題です。If cookies are used to store authentication tokens and to authenticate API requests on the server, CSRF is a potential problem. トークンの保存にローカルストレージを使用すると CSRF の脆弱性が軽減される可能性があります。なぜならローカルストレージの値は、全ての要求は自動でサーバーに送信されないからです。If local storage is used to store the token, CSRF vulnerability might be mitigated because values from local storage aren't sent automatically to the server with every request. したがって、クライアントの偽造防止トークンの保存にローカルストレージを使い、要求ヘッダーとしてトークンを送信することがお薦めのアプローチです。Thus, using local storage to store the antiforgery token on the client and sending the token as a request header is a recommended approach.

JavaScriptJavaScript

ビューで JavaScript を使うとビュー内でサービスを使ってトークンを作ることができます。Using JavaScript with views, the token can be created using a service from within the view. Microsoft.AspNetCore.Antiforgery.IAntiforgery サービスをビューに挿入して GetAndStoreTokens を呼び出します:Inject the Microsoft.AspNetCore.Antiforgery.IAntiforgery service into the view and call GetAndStoreTokens:

@{
    ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<input type="hidden" id="RequestVerificationToken" 
       name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<div class="row">
    <p><input type="button" id="antiforgery" value="Antiforgery"></p>
    <script>
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == XMLHttpRequest.DONE) {
                if (xhttp.status == 200) {
                    alert(xhttp.responseText);
                } else {
                    alert('There was an error processing the AJAX request.');
                }
            }
        };

        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById("antiforgery").onclick = function () {
                xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
                xhttp.setRequestHeader("RequestVerificationToken", 
                    document.getElementById('RequestVerificationToken').value);
                xhttp.send();
            }
        });
    </script>
</div>

このアプローチで、サーバーから Cookie を設定したりクライアントから Cookie を読み取る必要が無くなります。This approach eliminates the need to deal directly with setting cookies from the server or reading them from the client.

上の例では、JavaScript を使用して AJAX の POST のヘッダーの非表示フィールドの値を読み取ります。The preceding example uses JavaScript to read the hidden field value for the AJAX POST header.

JavaScriptは Cookie 内のトークンにアクセスし、その Cookie の内容を使ってトークンの値を持つヘッダーを作成することもできます。JavaScript can also access tokens in cookies and use the cookie's contents to create a header with the token's value.

context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, 
    new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });

スクリプトが X-CSRF-TOKEN というヘッダーでトークンの送信を要求すると想定して、X-CSRF-TOKEN ヘッダーを探すように偽造防止サービスを構成します:Assuming the script requests to send the token in a header called X-CSRF-TOKEN, configure the antiforgery service to look for the X-CSRF-TOKEN header:

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");

次の例は、JavaScript を使用して適切なヘッダーで AJAX の要求をします:The following example uses JavaScript to make an AJAX request with the appropriate header:

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i <ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

var csrfToken = getCookie("CSRF-TOKEN");

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (xhttp.readyState == XMLHttpRequest.DONE) {
        if (xhttp.status == 200) {
            alert(xhttp.responseText);
        } else {
            alert('There was an error processing the AJAX request.');
        }
    }
};
xhttp.open('POST', '/api/password/changepassword', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "newPassword": "ReallySecurePassword999$$$" }));

AngularJSAngularJS

AngularJS では CSRF に対処する規約があります。AngularJS uses a convention to address CSRF. サーバーが XSRF-TOKEN という名前の Cookie を送信すると、AngularJS の $http サービスはサーバーに要求を送信するとき、ヘッダーに Cookie の値を追加します。If the server sends a cookie with the name XSRF-TOKEN, the AngularJS $http service adds the cookie value to a header when it sends a request to the server. このプロセスは自動です。This process is automatic. クライアントで明示的にヘッダーを設定する必要はありません。The header doesn't need to be set in the client explicitly. ヘッダーの名前は X-XSRF-TOKEN です。The header name is X-XSRF-TOKEN. サーバーはこのヘッダー検出して検証する必要があります。The server should detect this header and validate its contents.

ASP.NET Core の API では、アプリケーションの起動時にこの規約が動作するようにします:For ASP.NET Core API to work with this convention in your application startup:

  • XSRF-TOKEN という Cookie にトークンを提供するようにアプリを構成するConfigure your app to provide a token in a cookie called XSRF-TOKEN.
  • X-XSRF-TOKEN という名前のヘッダーを探すように偽造防止サービスを構成するConfigure the antiforgery service to look for a header named X-XSRF-TOKEN.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (
            string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            // The request token can be sent as a JavaScript-readable cookie, 
            // and Angular uses it by default.
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

public void ConfigureServices(IServiceCollection services)
{
    // Angular's default header name for sending the XSRF token.
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

偽造防止の拡張Extend antiforgery

開発者は、IAntiForgeryAdditionalDataProvider 型を使用して各トークンの追加のデータをラウンドトリップすることで、CSRF 対策の動作を拡張できます。The IAntiForgeryAdditionalDataProvider type allows developers to extend the behavior of the anti-CSRF system by round-tripping additional data in each token. GetAdditionalData メソッドは、フィールドトークンが生成される度に呼ばれ、戻り値は生成されたトークン内に埋め込まれます。The GetAdditionalData method is called each time a field token is generated, and the return value is embedded within the generated token. 実装する人は、タイムスタンプ、nonce、その他の値を返しトークンが検証されたときにデータを検証するために ValidateAdditionalData を呼ぶことができます。An implementer could return a timestamp, a nonce, or any other value and then call ValidateAdditionalData to validate this data when the token is validated. クライアントのユーザー名は既に生成されたトークンに埋め込まれているので、この情報を含める必要はありません。The client's username is already embedded in the generated tokens, so there's no need to include this information. トークンに補足のデータが含まれていても IAntiForgeryAdditionalDataProvider が構成されていなければ、補足のデータは検証されません。If a token includes supplemental data but no IAntiForgeryAdditionalDataProvider is configured, the supplemental data isn't validated.

その他の技術情報Additional resources