【问题标题】:__RequestVerificationToken is not always being created__RequestVerificationToken 并不总是被创建
【发布时间】:2018-03-22 20:25:24
【问题描述】:

我们有一个包含多个表单的页面。每个都有自己的@Html.AntiForgeryToken()。在我的本地机器上一切都很好。

我们已部署到 Azure (PAAS),但 __RequestVerificationToken不是在每个请求上都创建。有时它在那里,有时我得到 The required anti-forgery cookie is not present,而且我很少得到 tokens do not match 错误

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

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

【问题讨论】:

  • 你找到答案了吗?
  • 不,我们必须删除防伪检查(它用于简单的集成表格。对此没有什么重要的)。我们的 Azure 设置有两个逻辑 CD,所以我猜这与处理请求和响应的不同 CD 有关。这只是我的猜测。
  • 听到这个消息我很难过,但我认为这应该不是问题,除非您在表单操作中也定义了域(然后将用户重定向到另一张 CD POST,但我怀疑情况是否如此,因为如果您使用 UrlHelper,则不会在域之间重定向用户)。
  • 注意你可以在一个页面内使用多个带有antifourgerytoken的表单,第二个你不能通过GET请求发送,第三个你不能在调用Html.AntiForgeryToken(salt)时使用不同的盐值,第四个使用AJAX可能需要额外的工作来确保令牌包含在POST中,所以除非你分享你的一些代码,否则我无法回答这个问题!
  • 您在尝试提交表单时遇到过失败,还是只是在某处审核了失败?

标签: asp.net-mvc azure antiforgerytoken


【解决方案1】:

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

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

This answer 包含针对具有多种形式的页面的可能解决方案,但正如here 所述,它具有一些安全缺陷。

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

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

  1. 带有返回 HTTP 标头和表单防伪令牌的原始页面请求。
  2. 带有已发送 HTTP 标头的 POST 请求。

【讨论】:

  • 根据 OP 的帖子,问题不是令牌不匹配(顺便说一句,如果您有多个令牌),而且似乎也不是一个始终存在的问题。此外,ASP.NET 在比较之前会解密防伪令牌。如果它们都包含与 cookie 对应的数据,那么表单中是否有 2 个不同的标记并不重要。此外,我在自己的系统中看到多个表单和表单令牌不是问题,问题是浏览器根本没有发送 cookie。
  • 确实,令牌不只是作为二进制缓冲区进行比较,而是通过保存在内部的安全令牌进行解密和比较。关于防伪令牌内部的好文章:codeproject.com/Articles/793384/…。 OP 提到有时他会得到“令牌不匹配错误”,所以我的假设仍然可能是一个问题。如果不是,那么我在答案底部要求的信息至少应该澄清这是本地客户端还是远程服务器的问题。
【解决方案2】:

在花费大量时间进行调查后,结合使用 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. Anti-Forgery cookie 分配在任何页面上,即使该页面没有表单,并且
  2. Anti-Forgery 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)
    {
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 2015-09-16
    • 2018-06-26
    • 2014-08-23
    • 2015-12-06
    • 1970-01-01
    相关资源
    最近更新 更多