问题 ASP.NET MVC - ValidateAntiForgeryToken到期


在网页中,我们提供了用户可以点击进行身份验证的超链接(GET):

@Html.ActionLink("Please Login", "MyMethod", "MyController")

这将映射到以下返回视图的控制器方法:

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

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

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

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

这很好用,大部分时间......

但是,如果用户将浏览器打开一段“重要”时间,然后快速连续执行以下步骤:

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

他们得到一个例外,告知他们Anti-Forgery令牌未提供或无效。

我不明白为什么会这样:View(包含表单)是在浏览器处于休眠状态之后创建的,因此防伪标记应该都是“新鲜的”。但是,这个设计显然有些问题,但我不确定如何最好地纠正它。

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

格里夫


11888
2017-10-01 18:32


起源

我只想提一下我的应用程序已经遇到这个问题几年了,我很乐意有一个解决方案。我尝试了所有标准的机器密钥修复程序。 - Jonathan
卷起那些袖子,潜入水源。我会说泵。 - Nick
有一个 文章 其中详细说明了令牌的验证步骤。一步是验证Context的用户 - 不确定这可能是不合时宜的。无论哪种方式,解决方案仍然不清楚。 - DrGriff


答案:


我正在处理同样的问题,虽然我理解这个问题,但我还不确定最佳解决方案。

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

RequestVerficationToken cookie的到期值设置为Session。因此,当用户长时间在页面上打开浏览器然后提交时,将cookie的时间戳与服务器上的会话超时值进行比较 - 默认值为20分钟左右 - 并且已超出,将被删除因此令牌验证失败。

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

  1. 在页面上放置一个javascript计时器,并刷新一些值 比你的会话超时。
  2. 在服务器上捕获System.Web.Mvc.HttpAntiForgeryException - 并重定向 到同一页面。
  3. 增加会话超时
  4. 更改防伪令牌的到期日期

10
2018-04-10 18:34



请注意,据我所知,机器密钥用于验证服务器上的Anti-ForgeryToken,并且是在webfarm中使用所必需的(并且设置静态机器密钥可能会解决因重新启动工作进程而导致的错误情况服务器),但它不会解决cookie过期问题。 - Gene Reddick
正如您所说,cookie过期与会话绑定,因此解决方案3也应该导致解决方案4.除非您手动覆盖cookie以某种方式生成的方式。我过去尝试过解决方案1并且它并不总是完全可靠,所以3(如果可能)和2的组合似乎是最好的选择。 - Rowan