在未进行身份验证的外部消费者(应用程序)中使用ASP.NET Core 6 Web API防伪令牌。

8

如何在ASP.NET Core 6 Web API中使用防伪标记,并与外部消费者(如iOS或Android应用程序)一起使用? 我不需要请求的用户身份验证。 应用程序托管在另一个域上。

我已经开发了一个带有Antiforgery Token的Web API(请参见此链接),以及ASP.NET 6 Razor Pages。 一切都运作得很完美。但是,我该如何开发一个使用此Web API的外部应用程序?问题是,我不知道如何从“外部”应用程序创建Antiforgery Token?我该如何配置应用程序以使用具有Antiforgery Token的Web API?

3个回答

7
当构建API时,不需要实现Anti-Forgery Token防止CSRF攻击,因为API的构建和使用目的需要不同的保护方法,例如:
- 使用API密钥。 - 使用基本身份验证。 - 使用OpenID Connect。
因为目标是防止恶意客户端调用我们的API,所以我们需要验证执行请求到API的客户端应用程序的身份。
而要执行CSRF攻击,其中一个主要条件是具有基于Cookie的身份验证会话(请参阅这篇文章,其中详细解释了如何执行CSRF攻击),但这在API中不是情况。
但是,如果您从与网站相同的来源调用API,并依赖Cookie对用户进行身份验证,则可以(并且应该)集成Anti-Forgery Token保护。您可以查看StackOverflow上的答案以获取更多有关如何实现它的详细信息。

但是,既然您将从外部应用程序调用API,只需使用上述方法之一。

请查看Microsoft文档上有关CSRF攻击以及如何实现防伪造令牌保护的更多详细信息。

另外,请查看RedHat的这篇文章,以获取有关API安全性的更多信息。


1
关于不需要使用防伪令牌的一刀切说法是错误的。 - undefined

3

我不同意“在构建API时不需要实现Anti-Forgery Token保护来防止CSRF攻击”的答案。

仍然存在风险,入侵者可能会以某种方式强制客户端应用程序发送恶意请求。


要在.NET Web API中配置Anti-Forgery保护(而不使用MVC Views),您需要使用包Microsoft.AspNetCore.Antiforgery

Keep in mind that there are two tokens which are being validated: a Cookie Token and a Request Token (from an HTTP header).

// Field
IAntiforgery _antiforgery;

var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

As a result, tokens will contain the value:

{
    "CookieToken": "CfDJ8JPuS3COPd9AmHCMBz_IFVdVzR8cfeD2or9v3qMLlWgRiN812hKbkh4o8TpYl4AdA3uJ3FeoY3eozx59q_uSnloXl80nLEd6twLzkDdn4AifcsGWcwaAxWSrGTui0vwl7-SHjftCfkbj9pAlDC_DS0Q",
    // Ignore this: built-in mechanism for forms
    "FormFieldName": "__RequestVerificationToken",
    "HeaderName": "X-XSRF-TOKEN",
    "RequestToken": "CfDJ8JPuS3COPd9AmHCMBz_IFVfnP50wBywG2WJmFoYA7nx-VGzBjPRY16-p3BBFRMUGHt4cz-M-VrZ_jX_7vUoIt0OX3xhHNw8swt0CebGa4P41cVej2F_DvvayOvrhbY6s3Z2U1aZWHmAvBT8NlH7ueRE"
}

Note that CookieToken and RequestToken are different.

Cookie Token is handled automatically. But Request Token should be handled by us.

  1. Create a validation middleware:

    public class AntiforgeryMiddleware : IMiddleware
    {
        private readonly IAntiforgery _antiforgery;
    
        public AntiforgeryMiddleware(IAntiforgery antiforgery)
        {
            _antiforgery = antiforgery;
        }
    
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var isGetRequest = string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase);
            if (!isGetRequest)
            {
                await _antiforgery.ValidateRequestAsync(context);
            }
    
            await next(context);
        }
    }
    
  2. Configure DI in your Web API application:

    // Startup.cs
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
    
        // Extension method comes from the `Microsoft.AspNetCore.Antiforgery` package
        services.AddAntiforgery(options =>
        {
            options.HeaderName = "X-XSRF-TOKEN";
        });
    
        services.AddScoped<AntiforgeryMiddleware>();
    }
    
  3. Configure a validation middleware:

    // Startup.cs
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ...
    
        app.UseMiddleware<AntiforgeryMiddleware>();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    
  4. Create a XSRF Token endpoint:

    [Route("api/xsrf-token")]
    [ApiController]
    public class AntiForgeryController : Controller
    {
        private IAntiforgery _antiforgery;
    
        public AntiForgeryController(IAntiforgery antiforgery)
        {
            _antiforgery = antiforgery;
        }
    
        [IgnoreAntiforgeryToken]
        public IActionResult Get()
        {
            // Creates and sets the cookie token in a cookie
            // Cookie name will be like ".AspNetCore.Antiforgery.pG4SaGh5yDI"
            var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
    
            // Take request token (which is different from a cookie token)
            var headerToken = tokens.RequestToken;
            // Set another cookie for a request token
            Response.Cookies.Append("XSRF-TOKEN", headerToken, new CookieOptions
            {
                HttpOnly = false
            });
            return NoContent();
        }
    }
    
  5. On the client make a request to the URL /api/xsrf-token.

    Then read a request token cookie XSRF-TOKEN and set it to a X-XSRF-TOKEN HTTP header for non-GET requests:

    X-XSRF-TOKEN: <request-token>
    

7
但是每个人都可以发出一个请求 /api/xsrf-token 来获取令牌,这里的安全性在哪里? - Denis
1
你对这篇写在微软文档中的文章有什么看法?“如果令牌存储在浏览器的本地存储中,就不必担心 CSRF 漏洞。当令牌存储在 cookie 中时,CSRF 就成为了一个问题。更多信息详见 GitHub 问题SPA 代码示例添加了两个 cookie。” 链接 - r_piramoon
1
是的,这就是自讨苦吃... XSRF问题仅限于Cookie授权。每个浏览器都会自动附加存储的cookie以匹配域名的每个请求。XSRF-TOKEN存储在cookie中,因此它将被发送到伪造的请求并在服务器上被接受。 为使其真正安全: 1)您需要使用Rest API的Session(从技术上讲应该是无状态的)2)在呈现表单之前调用您的AntiForgery端点将其存储在Session中3)在HTML表单隐藏字段中存储令牌4)在POST中将其发送到表单数据并与Session值进行比较。在负载平衡环境中祝您好运... - Major
即使在MVC中我们正在保护表单,但CSRF攻击对POST请求仍然很危险。此外,在异步方法中使用.GetAwaiter().GetResult()是完全不必要的,只需调用await即可。 - Major
有没有想法为什么我一直收到“所需的防伪 cookie“.AspNetCore.Antiforgery.Uxdfa43Kd“不存在”的错误消息。我已经检查了类似下面的答案,但在这个特定的实现中,cookie/header 的名称似乎有问题。我需要确切的名称是什么?请帮忙。 其他答案提到需要将其添加到 CORS。请帮忙。 - undefined

3

我之前曾经是一个安全冠军,所以知道什么是安全(但最近没有跟进这个话题)。但在每个会议或培训中通常有两件事是真实的:

  1. 安全很难做到正确...
  2. 安全非常非常难做到正确...所以永远不要自己来做!!

在您的情况下,问题在于Antiforgery Token(CSRF保护)在API中不可用。它只在MVC中可用,有充分的理由:

  • MVC使用会话并在服务器上呈现表单,因此在服务器端生成令牌,将其发送到HTML表单并存储在用户会话中以进行POST返回验证。
  • 大多数MVC站点都使用基于Cookie的身份验证,受CSRF post攻击影响。
  • REST API应该是无状态的,这意味着默认情况下没有会话。响应不是HTML,而是XML / JSON数据。 "Form" POST发生在其他系统中,并且安全地公开Antiforgery令牌。
  • 大多数RestFul API都使用oAuth2或某些Bearer令牌身份验证,甚至不受CSRF的影响!!!
所以对于你的问题,答案是另一个问题。你在API中使用基于Cookie的授权吗?如果不是,那么你不应该使用Antiforgery令牌,因为它不会影响你的API...否则,你应该切换到Bearer Auth头,然后就可以了。此外,请忽略编码的答案,因为它们存在许多问题。实现将编译,代码肯定运行,但是充满了安全问题(自制安全)。例如,令牌存储在Cookie中,这是CSRF攻击的基础,浏览器自动附加的Cookie到请求中,GET方法是安全的,甚至不能受到保护等等...自制安全可能会给人虚假的信心(是的,我“确保”了它),但它是否安全呢?

Homebrew security failed...


你会把令牌存储在客户端的哪个位置? - undefined
@IEnjoyEatingVegetables,不确定你的问题与原问题和我的回答有什么关系。如果你使用Bearer/JWT令牌,你就不会有CSRF攻击的风险。这种攻击只适用于Cookies,并且只有在使用Cookies进行身份验证时才需要使用AntiforgeryTokens...另外,不确定你的客户端应用是什么?假设它是Web浏览器,你可以将其存储在浏览器的本地存储中,或者如果你希望在关闭浏览器时自动注销,则可以存储在“会话存储”中。 - undefined
1
我之所以问是因为将JWT存储在本地存储中以在身份验证标头中使用会使您容易受到XSS攻击的威胁。 - undefined
这个问题是关于“反伪造令牌”,它是为了防止 CSRF(跨站点请求伪造)攻击而引入的。当攻击者在网站中创建一个隐藏的假HTML表单,并希望用户已经使用Cookie登录时。当假表单被提交时,浏览器会附加认证/会话Cookie。所以这是一个很大的风险... XSS(跨站点脚本)是完全不同的。攻击者会用HTML/JS片段填充您的表单,然后您将其保存到数据库中。下次当保存的数据加载到浏览器中时,它将被执行。您需要使用消毒剂来防止它。浏览器存储中的JWT与上述任何攻击都没有关系... - undefined
@IEnjoyEatingVegetables 请阅读OWASP关于安全的页面。因为提及与问题无关的其他攻击类型可能会引起困惑,同时也会提到并非真正存在的风险...https://owasp.org/search/?searchString=xss 还请查看我的更长的评论。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接