【问题标题】:Why does @Html.AntiForgeryToken() generate different tokens in same response?为什么@Html.AntiForgeryToken() 在同一个响应中生成不同的令牌?
【发布时间】:2014-04-24 01:50:07
【问题描述】:

单个 Razor 视图包含多个表单,每个表单都有自己对 @Html.AntiForgeryToken() 的调用

<form id="f1">
    @Html.AntiForgeryToken()
</form>

<form id="f2">
    @Html.AntiForgeryToken()
</form>

据我了解,这两个防伪令牌应该是相同的。

<form id="f1">
    <input name="__RequestVerificationToken" type="hidden" value="duVT4VtiYybun-61lnSY1ol__qBwawnELooyqT5OSrCJrvcHvDs_Nr9GLxNxwvBaI4hUcKZVkm6mDEmH2UqNorHD1FnJbKJQLWe8Su_dhy_nnGGl5GhqqC3yRGzcxbBM0" />
</form>

<form id="f2">
    <input name="__RequestVerificationToken" type="hidden" value="ZMISz3IWHU_HCKP4FppDQ5lvzoYhlQGhN1cmzKBPz4OgDzyqSUK3Q1dqvw1uHsb4eNyd9U3AbFcnW8tR7g1QS8Dyhp0tFc-ee1sfDAOqbLCcgd3PDnLCbXx09pnPREaq0" />
</form>

为什么值不同?

当然它们应该是相同的,因为它们是在服务器的相同响应中发送的?
documentation 没有说只调用一次。

【问题讨论】:

  • 请记住,vtortola 的方法会产生安全漏洞,正如我在下面的回答中所解释的那样。令牌必须不同。

标签: asp.net-mvc security asp.net-mvc-4 razor antiforgerytoken


【解决方案1】:

这些不是等同的 antiforgerytoken 命令

MVC 为所有 uniqe 命令生成 uniqe。

所以您不应该等待生成的相同 ID。据我所知:)

谢谢你,buffjape,你的评论

【讨论】:

  • 将它们放在相同的形式中没有区别。对@Html.AntiForgeryToken() 的两次调用总是生成不同的值。
  • 我认为浏览器的错误有时会导致这样的问题。
【解决方案2】:

恐怕这行不通。

防伪令牌也在响应 cookie 中传播,因此您的将只包含最后一个令牌,因此第一个表单将始终失败。

你可以尝试做这样的事情:

@{
    ViewBag.Title = "Index";
    var token = Html.AntiForgeryToken();
}

<form id="f1">
    @token 
</form>

<form id="f2">
    @token 
</form>

我试过了,两种形式都用了同一个token。

【讨论】:

  • 你知道为什么值不同吗?
  • 因为每次调用都会生成不同的令牌,也就是说,没有更多可挖掘的了。 MSDN 说“生成一个隐藏的表单字段(防伪令牌),在提交表单时进行验证。”,因此“生成”声明每次都会生成一个新字段:)
  • 因为如果每次调用它都返回相同的token,那么你会在不同的页面上得到相同的token,并且有人可以复制它来进行CSRF攻击。如果您需要在两个不同的地方使用令牌(因为您的页面有两种形式),那么这是正确的答案。
  • 这没有错。制作此助手的开发人员决定每次调用生成一次。那就是API。这是开发人员的决定(可能很多人参与了进来)。如果您喜欢您描述的行为,请自己实现——这就是编程的美妙之处!
  • 您的方法会造成安全漏洞,如我在下面提供的答案中所述。您不应该对页面中存在的每个表单使用相同的令牌。
【解决方案3】:

肯定它们应该是相同的,因为它们是在同一个响应中发送的?

响应与它无关。 @Html.AntiForgeryToken()HtmlHelper 的一个静态方法,它生成一个 unique 标记,该标记添加到 html 和响应 cookie。您多次调用该方法,以便生成多个令牌。

如果它每次都没有生成唯一的令牌,那么它几乎不会是安全的。

【讨论】:

  • 对不起,我的意思是响应而不是请求。问题已修改,但仍然存在 - 为什么在 cookie 中只有一个标记时在 HTML 中生成两个不同的标记?
  • @buffjape,我不明白为什么您认为调用返回 unique 值的方法会或可能会返回重复值 - 这是不可能的。它与创建具有var a = Guid.NewGuid; var b = Guid.NewGuid; 的方法没有什么不同ab 的值将不同。根据您的逻辑,它们应该是平等的,因为它们采用相同的方法。或许你应该研究一下source code 以获得更好的理解
  • 据我了解,@Html.AntiForgeryToken() 的目的是在页面上放置一个特定的防伪令牌(使其与 cookie 匹配)。我已经知道它不会那样做。我正在寻找的是一个合理的解释......
【解决方案4】:

@Html.AntiForgeryToken() 基本上是根据 cookie 和表单数据生成加密值。因此,如果您为每个声明并使用此@Html.AntiForgeryToken(),它将生成两个不同的_RequestValidationToken。最好使用@Html.AntiForgeryToken() 方法声明一个全局@token 变量,它将为每个请求创建一个令牌。

【讨论】:

    【解决方案5】:

    必须不同。不是因为实现内部工作或 API voodoo,而是因为每个表单都代表对服务器的独立请求。

    如果表单具有相同的令牌,一旦攻击者知道一个表单的令牌值,他就能够欺骗服务器接受其他表单发送的数据,尽管它们不是由用户提交的,从而击败了AntiCSRF Token 提供的保护。

    令牌的目的是提供一个随机的 id 参数,使攻击者很难欺骗应用程序,使其认为是登录用户填写了表单。

    不了解CSRF攻击的朋友可以看看here

    【讨论】:

    • 那么攻击者如何获得其中一种形式的token呢?
    • MitM 是看到这一点的方法之一。 DNS中毒将是另一种。击败"same-origin policy" (even android browser suffers from this) 的攻击也将使攻击者能够读取页面内容,从而允许他通过 javascript 读取令牌。
    • 这也适用于具有一个防伪令牌的一种形式。如果可能发生中间人攻击,您的令牌将从 HTML 响应和 Set-Cookie HTTP 标头中看到。即使中间人只允许从客户端拦截到服务器,攻击者仍然可以在不知道令牌的情况下更改您发送的数据。此外,如果攻击者可以读取您在浏览器中的页面,那么您是拥有一种形式的一个令牌还是两种形式的两个令牌都没有关系。
    • 如果安全令牌在使用时没有失效,我创建自己的管理员用户所需要做的就是重播原始请求,只需更改所选凭据。
    • owasp.org/index.php/…,特别是当它说:“一般来说,开发者只需要为当前会话生成一次这个令牌。”
    【解决方案6】:

    Anti-Forgery 令牌不直接比较 - 服务器必须首先取消保护它并比较内部受保护的数据。拥有不同的受保护令牌并不一定意味着它们包含不同的数据。

    System.Web.Helpers.AntiXsrf.TokenValidator 比较的是解密后的AntiForgeryToken 实例中的SecurityToken。然而,这些实例还包含一个AdditionalData 字段、一个UserName 字段和一个ClaimUid 字段。

    另外,AntiForgeryToken 中的SecurityToken 直接从AntiForgeryWorker 中的(如果有效则为当前,否则为新生成的)AntiForgery cookie 复制。

    鉴于所有数据都经过序列化、加密然后编码,由于令牌之间的 AdditionalData 之间的差异,您可能会在受保护令牌中产生差异,或者 这可能是由于加密过程中使用了伪随机数(它可能会使用它,因为我可以测试 2 个完全不同的令牌是否对同一个 cookie 有效)。

    【讨论】:

      猜你喜欢
      • 2019-09-25
      • 1970-01-01
      • 2019-06-17
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      相关资源
      最近更新 更多