在单个页面上为多个表单生成CSRF令牌

时间:2013-02-05 19:21:53

标签: security csrf

我目前正在表单中生成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>

这种不安全吗?它简化了一些事情,因为我可以简单地将安全令牌附加到body元素,而不是处理多个安全令牌。

感谢您的见解和评论。

2 个答案:

答案 0 :(得分:15)

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

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

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

答案 1 :(得分:2)

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

OWASP Guide说:

  

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

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

使用单独的令牌只是有一个优势,如果你以某种方式设法妥协一些但不是全部(非常不可能,因为例如XSS会危及所有这些),攻击者的选择将是有限的。