13

我目前正在CSRF我的表单中生成一个令牌以防止跨站点请求伪造。看起来像:

<form method="post" action="action.php">
   <input type="hidden" id="security_token" name="security_token" value="gTt96phAcretR99rafEjepHebrEZadEdezadagaZ3gAS5es33WReJeZaMADU2AWr" />
   ...
</form>

问题是我在一个页面上有多个表单。我必须为每个表单创建一个安全令牌吗security_token_1security_token_2或者我可以简单地而不是在表单内部生成安全令牌,而是将其附加到整个body标签的属性中,例如:

<body data-csrf-token="gTt96phAcretR99rafEjepHebrEZadEdezadagaZ3gAS5es33WReJeZaMADU2AWr">
...
</body>

这在任何方面都不安全吗?它简化了很多事情,因为我可以简单地将安全令牌附加到正文元素,而不是处理多个安全令牌。

感谢您的洞察力和评论。

4

2 回答 2

16

确实没有任何理由不能为两种表单生成相同的令牌,每个表单中的每个隐藏字段都具有相同的name属性。

毕竟,您真正要验证的是表单请求是来自具有有效会话的用户的入站请求,并且一次只会主动发布一个表单。因此,您将发布的令牌与存储在用户会话中的令牌进行比较。为了做到这一点,不需要多个令牌值。

对于您需要根据 AJAX 帖子更新令牌的情况,您需要做的是,正如您所说,将新创建的令牌传回 AJAX 响应中,然后将隐藏字段值更新为新令牌值。

于 2013-02-05T19:30:30.637 回答
3

只要您确保攻击者无法获得 CSRF 令牌(例如,不要将其包含在发送给第三方的表单中),使用单个 CSRF 令牌应该是可以的。请注意,使用您的“将其放入正文”方法,您将需要 JavaScript 来提交表单,因此即使您只使用一个中央标记,您可能仍希望将其插入到每个表单中。

OWASP 指南说:

通常,开发人员只需为当前会话生成一次此令牌。在初始生成此令牌后,该值将存储在会话中,并用于每个后续请求,直到会话到期。

即根本不需要使用多个令牌。

使用单独的令牌的好处是,如果您以某种方式设法破坏了其中的一些,但不是全部(几乎不可能,因为例如 XSS 会破坏所有令牌),攻击者的选择将受到限制。

于 2013-02-05T19:31:25.070 回答