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. 這些攻擊可能會因為網頁瀏覽器會將某些類型的驗證權杖會自動隨著每個要求傳送至網站。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.comThe 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 的 「 跨站台 」 部分。This is the "cross-site" part of CSRF.

  3. 使用者選取 [提交] 按鈕。The user selects the submit button. 瀏覽器提出要求,並會自動包含所要求的網域,驗證 cookie www.good-banking-site.comThe 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.

CSRF 攻擊是可能對 web 應用程式使用 cookie 進行驗證,因為: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.
  • 瀏覽器傳送的所有 cookie 與網域相關聯 web 應用程式無論在瀏覽器內產生應用程式的要求方式的每個要求。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、 重新建立主體,並將指派主體使用者屬性HttpContextOn subsequent requests, the middleware validates the cookie, recreates the principal, and assigns the principal to the User property of HttpContext.

權杖型驗證Token-based authentication

當驗證使用者時,會核發給這些語彙基元 (不 antiforgery 權杖)。When a user is authenticated, they're issued a token (not an antiforgery token). 權杖包含使用者資訊的形式宣告或指向維護應用程式中的使用者狀態的應用程式的參考語彙基元。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. CSRF 權杖儲存在 cookie 中時的考量。CSRF is a concern when the token is stored in a cookie.

裝載在一個網域的多個應用程式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 antiforgery 組態ASP.NET Core antiforgery configuration

警告

ASP.NET Core 會實作使用 antiforgery 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 antiforgery 權杖插入 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依預設會產生 antiforgery 權杖,如果表單的方法不是 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="")。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>
    
  • 表單項目是選擇外的標籤協助程式使用標籤協助程式! 退出符號: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 PagesFor more information, see XSRF/CSRF and Razor Pages.

對抗 CSRF 攻擊的最常見方法是使用同步器 Token 模式(spanning tree Protocol)。The most common approach to defending against CSRF attacks is to use the Synchronizer Token Pattern (STP). 當使用者要求包含表單資料的頁面時,會使用 spanning tree Protocol:STP is used when the user requests a page with form data:

  1. 伺服器會傳送至用戶端的目前使用者的身分識別相關聯的語彙基元。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. 如果伺服器收到不符合已驗證的使用者的身分識別的權杖,則會拒絕要求。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 頁面範本中的表單產生防偽語彙基元。All of the forms in ASP.NET Core MVC and Razor Pages templates generate antiforgery tokens. 下列配對檢視範例產生的防偽語彙基元:The following pair of view examples generate antiforgery tokens:

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

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

明確地將加入的 antiforgery 權杖<form>而不使用標籤協助程式與 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>

在每個上述所有情況下,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 包含三個篩選器使用防偽權杖:ASP.NET Core includes three filters for working with antiforgery tokens:

Antiforgery 選項Antiforgery options

來自訂antiforgery 選項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;
});

†設定 antiforgeryCookie屬性使用的屬性CookieBuilder類別。†Set the antiforgery Cookie properties using the properties of the CookieBuilder class.

選項Option 描述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". 預設值為 falseDefaults 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;
});
選項Option 描述Description
CookieCookie 決定用來建立防偽 cookie 的設定。Determines the settings used to create the antiforgery cookies.
CookieDomainCookieDomain Cookie 的網域。The domain of the cookie. 預設值為 nullDefaults to null. 這個屬性已經過時,將在未來版本中移除。This property is obsolete and will be removed in a future version. 建議的替代做法是 Cookie.Domain。The recommended alternative is Cookie.Domain.
CookieNameCookieName Cookie 的名稱。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. 預設值為 falseDefaults 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". 預設值為 falseDefaults to false.

如需詳細資訊,請參閱 CookieAuthenticationOptionsFor more information, see CookieAuthenticationOptions.

使用 IAntiforgery 設定 antiforgery 功能Configure antiforgery features with IAntiforgery

IAntiforgery提供的 API 來設定 antiforgery 的功能。IAntiforgery provides the API to configure antiforgery features. IAntiforgery 可在要求Configure方法的Startup類別。IAntiforgery can be requested in the Configure method of the Startup class. 下列範例會使用從應用程式的首頁上的中介軟體,以產生 antiforgery 權杖,並在回應中傳送 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 不支援自動將 antiforgery 權杖新增至 GET 要求。ASP.NET Core doesn't support adding antiforgery tokens to GET requests automatically.

會自動進行驗證不安全的 HTTP 方法只 antiforgery 的權杖Automatically validate antiforgery tokens for unsafe HTTP methods only

ASP.NET Core 應用程式不會產生安全的 HTTP 方法 (GET、 HEAD、 選項和追蹤) 的防偽語彙基元。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
  • 選項OPTIONS
  • TRACETRACE

我們建議使用AutoValidateAntiforgeryToken廣泛用於非 API 案例。We recommend use of AutoValidateAntiforgeryToken broadly for non-API scenarios. 這可確保預設受到保護後動作。This ensures POST actions are protected by default. 替代方法是忽略 antiforgery 權杖依預設,除非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. 所有貼文應該傳送的防偽語彙基元。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()));

覆寫全域或控制器 antiforgery 屬性Override global or controller antiforgery attributes

IgnoreAntiforgeryToken篩選器可用來消除對指定的 「 動作 」 (或稱 「 控制器 」) 的 antiforgery 權杖。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 頁面 頁面之後,就應該重新整理權杖。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 型應用程式,antiforgery 權杖會傳遞至使用隱藏的表單欄位的伺服器。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. 若要將 antiforgery 權杖儲存在用戶端和傳送權杖做為要求標頭是建議的方法,因此,使用本機儲存體。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,或從用戶端讀取。This approach eliminates the need to deal directly with setting cookies from the server or reading them from the client.

上述範例中使用 JavaScript 針對 POST 的 AJAX 標頭讀取隱藏的欄位值。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,將 antiforgery 服務設定為尋找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. 如果伺服器會傳送具有名稱的 cookie XSRF-TOKEN,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-TOKENThe 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:

  • 設定您的應用程式提供的權杖在 cookie 中稱為XSRF-TOKENConfigure your app to provide a token in a cookie called XSRF-TOKEN.
  • 將 antiforgery 服務設定為尋找標頭X-XSRF-TOKENConfigure 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)

擴充 antiforgeryExtend 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