AntiForgeryToken,具体来说,'match up' 如何使用 cookie?

How does AntiForgeryToken, specifically, 'match up' with a cookie?

我们有一个网页,上面有一个表格。通过帮助程序将防伪令牌添加到此 MVC 页面的表单中:

@Html.AntiForgeryToken()

我们今天意识到我们已经缓存了页面,我们认为这将是一个大问题,但是多台机器可能会提交相同的表单,即使它们在页面源中共享相同的验证令牌!?

据我所知,这是出乎意料的,我的想法是可以在 cookie 中找到相同的验证令牌?我显然误解了令牌背后的机制(在页面上和用户 cookie 的修改)。

有人可以向我解释此页面如何仍然有效吗? 更具体地说,服务器如何验证表单的 post 请求。

我认为这就像服务器检查令牌字符串是否与在 cookie 中找到的令牌字符串相同一样简单。

注意:暂时关闭缓存,我们对缓存带有令牌的页面不是 100% 满意,因为我们对它有了更多了解。

We realised today that we have the page cached, which we thought would be a massive issue, but multiple machines may submit the same form, even though they share the same verification token in the page's source!?

是的,就防伪令牌而言,缓存是一个问题。您有两个选择:

  1. 不缓存表单。
  2. 使用 OutputCacheVaryByCustom 属性 因令牌本身而异。

我手边没有代码,所以我将向您展示一个摘自 this 文章的示例:

In order to avoid this issue you can use the VaryByCustom property on the OutputCache attribute:

[OutputCache(
  Location = OutputCacheLocation.ServerAndClient,
  Duration = 600,
  VaryByParam = "none",
  VaryByCustom = "RequestVerificationTokenCookie")]
public ActionResult Index()
{
  return new View();
}

And then program the rule on the global.asax‘s GetVaryByCustomString method:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
  if (custom.Equals("RequestVerificationTokenCookie", StringComparison.OrdinalIgnoreCase))
  {
    string verificationTokenCookieName =
      context.Request.Cookies
        .Cast<string>()
        .FirstOrDefault(cn => cn.StartsWith("__requestverificationtoken", StringComparison.InvariantCultureIgnoreCase));
    if (!string.IsNullOrEmpty(verificationTokenCookieName))
    {
      return context.Request.Cookies[verificationTokenCookieName].Value;
    }
  }
  return base.GetVaryByCustomString(context, custom);
}

根据评论编辑

它起作用的原因是因为它只是将 cookie 的值与表单上生成的隐藏字段的值进行比较。如果您认为它可能以这种方式工作,则服务器上没有维护的令牌列表可供验证。这意味着,就客户端而言,尽管生成的表单缓存在服务器上,客户端仍会收到 'new' 表单,因此还会收到一个 cookie,因此比较不会失败的。