__RequestVerificationToken 并不总是被创建

问题描述 投票:0回答:3

我们有一个包含多种表单的页面。每个人都有自己的

@Html.AntiForgeryToken()
。在我的本地机器上一切都很棒。

我们部署到 Azure (PAAS),但

__RequestVerificationToken
并未根据每个请求创建。有时它在那里,有时我收到所需的防伪 cookie 不存在,很少收到令牌不匹配错误

我现在完全一无所知。我不知道我们的代码或Azure环境是否有问题?这些形式中没有 ajax。

我们已将

<machineKey>
部分添加到我们的 web.config 中。没有缓存。有时它从第一次就出现在新设备上。

asp.net-mvc azure antiforgerytoken
3个回答
3
投票

在花费大量时间进行调查后,结合使用 Sentry 和 Azure Web 服务器日志,我发现了上述错误的 2 个主要原因:

1)在手机上,当浏览器处于后台时,操作系统可能会突然停止浏览器以释放资源。发生这种情况时,通常页面会存储在手机驱动器上,并在重新打开浏览器后从那里重新加载。

然而,问题是,此时,防伪令牌(即会话 cookie)已经过期,因为这本质上是一个新会话。因此,页面加载时没有防伪 Cookie,而是使用上一个会话中的 HTML。这会导致

The required anti-forgery cookie is not present
异常。

2) 虽然看似相关,但

tokens do not match
例外通常只是无关紧要的相关。原因似乎是同时打开多个选项卡的用户行为。

仅当用户到达包含表单的页面时才会分配防伪 Cookie。这意味着他们可以访问您的主页,并且没有防伪 cookie。然后他们可以使用中键单击打开多个选项卡。多个选项卡是多个并行请求,每个请求都没有防伪 cookie。

由于这些请求没有防伪 cookie,因此 ASP.NET 会为每个请求生成一个单独的伪随机令牌,并在表单中使用该令牌;但是,仅保留最后接收到的标头的结果。这意味着所有其他页面将在页面上具有无效令牌,因为它们的防伪 cookie 已被覆盖。

对于解决方案,我创建了一个全局过滤器,应确保

  1. 防伪 cookie 分配在任何页面上,即使该页面没有表单,并且
  2. 防伪 cookie 不受会话限制。应调整其生命周期以匹配用户登录令牌,但它应在会话之间持续存在,以防移动设备在没有会话的情况下重新加载页面。

下面的代码是一个

FilterAttribute
,必须作为全局过滤器添加到
FilterConfig.cs
内。 请注意,虽然我不认为这会造成安全漏洞,但我绝不是安全专家,因此欢迎任何意见。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AntiForgeryFilter : FilterAttribute, IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var cookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName);
        var addCookie = true;
        if (string.IsNullOrEmpty(cookie?.Value))
        {
            cookie = filterContext.HttpContext.Response.Cookies.Get(AntiForgeryConfig.CookieName);
            addCookie = false;
        }
        if (string.IsNullOrEmpty(cookie?.Value))
        {
            AntiForgery.GetTokens(null, out string cookieToken, out string _);
            cookie = new HttpCookie(AntiForgeryConfig.CookieName, cookieToken)
            {
                HttpOnly = true,
                Secure = AntiForgeryConfig.RequireSsl
            };
        }
        cookie.Expires = DateTime.UtcNow.AddYears(1);
        if(addCookie) filterContext.HttpContext.Response.Cookies.Add(cookie);
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }
}

1
投票

我相信您的问题来自于在一页上有多个带有不同防伪令牌的表单。 当请求页面时,您会在表单隐藏字段中获得两个不同的令牌,但在 cookie 中仅获得一个令牌。 表单 POST 包含导致错误的不匹配标记。

如果页面仅包含一个表单,请尝试 AFT 如何为您工作。如果它工作正常那么我的假设是正确的。

这个答案包含具有多种表单的页面的可能解决方案,但它有一些安全缺陷,如here所述。

我不确定为什么在您的本地主机上一切正常。 我创建了简单的应用程序,并尝试使用正确的 cookies 令牌但使用上一个会话中的旧表单令牌来进行表单 POST。令我惊讶的是,这样的 POST 成功通过了。 在这种情况下,asp.net 可能对本地请求进行了一些特殊处理。我没有找到任何这方面的信息。

如果我的回答还是没有帮助到您,请您提供以下数据以供进一步分析:

  1. 原始页面请求,返回 HTTP 标头并形成防伪令牌。
  2. 使用发送的 HTTP 标头形成 POST 请求。

0
投票

只有在推送到服务器后,我才遇到同样的问题,在本地主机中测试后,情况很好,之后

© www.soinside.com 2019 - 2024. All rights reserved.