在ASP.NET Core AntiforgeryTokenSet中,RequestToken和CookieToken的用法有什么区别?

In an ASP.NET Core AntiforgeryTokenSet, what's the difference between the usage of RequestToken and CookieToken?

我们有一个 ASP.NET Core 2.2 Web 应用程序,带有一个使用 cookie 身份验证的 Angular SPA。

我正在按照 configure antiforgery features with IAntiforgery 的文档进行操作。

相关的代码片段是:

services.AddAntiforgery();
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);
    });
}

调用 antiforgery.GetAndStoreTokens(context) returns 具有 RequestTokenCookieToken 属性的 AntiforgeryTokenSet

如果我在默认配置下使用上面的代码,我会得到两个 cookie:.AspNetCore.Antiforgery.*(匹配 CookieToken)和 XSRF-TOKEN(匹配 RequestToken),其中不同的值。

RequestTokenCookieToken

在用法上有什么区别

XSRF-TOKEN:

这是一个 JavaScript-readable cookie,Angular 应用程序将读取它并作为 HTTP header 发回。

.AspNetCore.Antiforgery.*:

这是一个 HTTP-only cookie(即 而不是 JavaScript-readable),浏览器会将其作为典型的 cookie 发送回服务器。


ASP.NET Core 中的 CSRF 保护需要发送 HTTP header 和 cookie。它在验证请求时同时检查 header 和 cookie。如果缺少任何一个,验证将失败。

有两个 cookie 的原因是 ASP.NET 核心使用 Double Submit Cookie pattern, described in the OWASP Cross-Site Request Forgery (CSRF) Cheat Sheet

这篇优秀的文章,ASP.NET Core CSRF defence with Antiforgery describes the process in much more detail than the Microsoft documentation


...it provides a stateless defence mechanism composed of 2 items (or token set) that should be found on any request being validated by the Antiforgery package:

  • An antiforgery token included as a cookie, generated as a pseudorandom value and encrypted using the new Data Protection API

  • An additional token included either as a form field, header or cookie. This includes the same pseudorandom value, plus additional data from the current user’s identity. It is also encrypted using the Data Protection API.

These tokens will be generated server-side and propagated along with the html document to the user’s browser. The cookie token will be included by default whenever the browser sends a new request while the application needs to make sure the request token is also included. (We will see in the next sections how to do this)

A request will be then rejected if:

  • any of the 2 tokens is missing or have an incorrect format/encryption
  • their pseudorandom values are different
  • the user data embedded in the second token doesn’t match the currently authenticated user

In the case of Angular, you will be using their $http service for sending AJAX requests. This service will automatically include a header with the name X-XSRF-TOKEN if it can find the token value as a cookie with the name XSRF-TOKEN. So the easiest way is to play the way Angular wants us to, and create some middleware that will get the request token, and store its value as the XSRF-TOKEN cookie.

Even if it is added as a cookie, this is still the request token and not the cookie token! It might sound confusing, so let me try to clarify it:

The application will send back to the browser a cookie XSRF-TOKEN with the request token and another cookie .AspNetCore.Antiforgery.* with the cookie token. Whenever Angular sends an Ajax request, the request will include a header X-XSRF-TOKEN with the request token and the cookie .AspNetCore.Antiforgery.* with the cookie token. The Antiforgery validation will make sure that both tokens are valid and share the same secret, etc.


所以应该有两个cookie。在我的场景中,随每个请求一起发送的 .AspNetCore.Antiforgery.* cookie 构成令牌集的一半,然后 Angular 使用 XSRF-TOKEN 来设置 X-XSRF-TOKEN header 构成令牌集的另一半。


另请参阅: