ASP.NET MVC - 验证AntiForgeryToken过期

17
在网页中,我们提供一个超链接(GET请求),用户可以点击以进行身份验证:
@Html.ActionLink("Please Login", "MyMethod", "MyController")

这对应于以下控制器方法,该方法返回一个视图:

    [RequireHttps]
    public ActionResult MyMethod()
    {
        return this.View(new MyModel());
    }

此视图包含用户提供凭据的表单;该表单包含所需的AntiForgeryToken。

当用户提交表单时,将调用以下控制器方法:

    [HttpPost]
    [RequireHttps]
    [ValidateAntiForgeryToken]
    public ActionResult MyMethod(MyModel model)
    {
        // my logic
    }

这段代码在大多数情况下工作得非常好...

然而,如果用户让他们的浏览器处于“显著”的空闲状态,然后快速执行以下步骤:

  1. 单击超链接(GET)以加载登录表单
  2. 填写表单并提交

他们会收到一个异常消息,通知他们 Anti-Forgery 令牌未提供或无效。

我不明白为什么会出现这种情况:视图(包含表单)是在浏览器处于空闲状态之后创建的,因此防伪令牌应该都是“新鲜的”。不过,设计上显然存在问题,但我不确定如何最好地改正它。

如果您有任何建议,请提前致谢。

Griff


我只想提一下,我的应用程序已经遇到这个问题几年了,我希望能够找到一个解决方案。我尝试了所有标准的机器密钥修复方法。 - Jonathan
卷起袖子,深入源代码。我来操作泵。 - Nick
有一篇文章详细介绍了令牌验证步骤。其中一步是针对上下文用户进行验证 - 不确定是否可能已经失效。无论如何,解决方案仍然不清楚。 - DrGriff
1个回答

19

我也遇到了这个问题,虽然我理解了这个问题,但我还不确定最佳的解决方案。

Anti-ForgeryToken过程将一个输入值放置在表单中,并将第二个值存储在名为RequestVerificationToken的cookie中。这两个值都提交给服务器,如果它们不匹配,则会抛出错误。

RequestVerficationToken cookie的过期时间设置为Session。因此,当用户长时间保持浏览器打开页面,然后提交时,将比较cookie的时间戳和服务器上的会话超时值(默认为大约20分钟),并且由于已经超出,因此被删除,从而令令牌验证失败。

可能的解决方案,所有这些方案都有潜在的问题;

  1. 在页面上设置javascript计时器,并在小于会话超时的某个值上刷新。
  2. 捕获服务器上的System.Web.Mvc.HttpAntiForgeryException错误,并重定向到同一页面。
  3. 增加会话超时时间。
  4. 更改防伪标记的过期时间。

1
请注意,据我所了解,机器密钥用于在服务器上验证防伪令牌,并且在 WebFarm 中使用时是必需的(设置静态机器密钥可能会解决由服务器上工作进程重新启动引起的错误情况),但它无法解决 cookie 过期问题。 - Gene Reddick
正如你所说,Cookie的过期时间与Session相关联,因此解决方案3也应该导致解决方案4。除非你以某种方式手动覆盖了Cookie的生成方式。我之前尝试过解决方案1,但它并不总是完全可靠,因此结合使用解决方案3(如果可能)和2似乎是最好的选择。 - Rowan

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