防伪标记是可重复使用的

Swi*_*ger 16 c# asp.net asp.net-mvc csrf antiforgerytoken

我们使用ASP.NET MVC的默认Antiforgery技术.最近,一家安全公司对表单进行了扫描,并注意到他们可以_RequestVerificationToken多次使用相同的组合(cookie +隐藏字段).或者他们如何表达:"正文中的CSRF令牌在服务器端验证,但在使用后即使服务器生成新的CSRF令牌也不会被撤销."

在阅读了关于Antiforgery实现的文档和多篇文章之后,我的理解是,只要会话用户匹配令牌中的用户,这确实是可能的.

他们的部分推荐:"这样的令牌至少应该是每个用户会话的唯一性" 在我的理解中已经是这种情况,除了匿名用户,对吗?

我的问题:这是一个安全问题吗?这有多大的风险?是否有一个库确保令牌不可重复使用/无效.

如果没有,包括会话中的额外随机令牌将在每个请求上重置,听起来就像解决问题一样.

Swi*_*ger 5

客户最终同意,ASP.NET的防伪实现已足够。只是为了好玩,我想扩展防伪以满足无效要求。

Antiforgery库具有一个扩展点:IAntiforgeryAdditionalDataProviderCore)和IAntiForgeryAdditionalDataProviderpre-Core

在ASP.NET MVC(预核心)中,可以在启动时进行设置。

using System.Web;
using System.Web.Helpers;
// ...

namespace AntiForgeryStrategiesPreCore
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            // ...
            AntiForgeryConfig.AdditionalDataProvider = new MyAdditionalDataProvider();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于ASP.NET Core,您需要将其注册IAntiforgeryAdditionalDataProvider为服务。如果不这样做,它将使用DefaultAntiforgeryAdditionalDataProvidersource)不执行任何操作。

using System;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace AntiForgeryStrategiesCore
{
    // ...

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IAntiforgeryAdditionalDataProvider, SingleTokenAntiforgeryAdditionalDataProvider>();
            // ...
        }
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以将其他数据添加到您的Antiforgery令牌中,该数据将插入到cookie和form字段中。这是一个MVC Core示例,该示例保留Session中的单个令牌,并在使用后将其删除。

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;

namespace AntiForgeryStrategiesCore
{
    public class SingleTokenAntiforgeryAdditionalDataProvider : IAntiforgeryAdditionalDataProvider
    {
        private const string TokenKey = "SingleTokenKey";

        public string GetAdditionalData(HttpContext context)
        {
            var token = TokenGenerator.GetRandomToken();
            context.Session.SetString(TokenKey, token);
            return token;
        }

        public bool ValidateAdditionalData(HttpContext context, string additionalData)
        {
            var token = context.Session.GetString(TokenKey);
            context.Session.Remove(TokenKey);
            return token == additionalData;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不建议这样做,因为当您打开具有多个表单的多个选项卡时,只有一个表单在会话中具有有效令牌,而另一个将失败。这就是为什么我制作了一个可以保留多个令牌的原因。您可以在GitHub上找到AdditionalDataProvider和其他(基于时间,基于队列)。