网站在多个选项卡中打开时的csrf哈希标记行为

时间:2011-12-02 00:02:19

标签: forms csrf

我正在尝试集成一种方法,为我的应用程序中的每个表单添加一个哈希标记。我想通过这个实现目标:

  1. 防止csrf攻击
  2. 当用户在提交表单后重新加载页面时,防止重新提交表单
  3. 现在,我想这样做的概念应该很简单:

    • 我生成一个唯一的哈希并将其保存到cookie
    • 我使用生成的哈希
    • 在表单中创建一个隐藏字段
    • 在从表单处理$ _POST数据之前,我验证表单中的哈希值是否与cookie中的哈希值匹配。

    到目前为止一切顺利,现在我真正陷入困境的是以下情况:

    如果用户使用我的应用程序打开另一个选项卡,该怎么办?每次加载页面时,都会重新生成哈希值。因此,从第一个选项卡中的表单呈现哈希值无效。

2 个答案:

答案 0 :(得分:2)

不要将令牌存储为cookie。

在每个页面展示上生成唯一标记。在POST时,验证您是否已向该用户发出令牌并验证它之前是否已被使用过。

首先,我们生成一个令牌,我们可以验证我们是否为给定用户发布了它:

token = hash(session_id + secret)

这样,使用他们的会话ID和我们的秘密,我们总能验证我们发出了这个令牌,因为没有人知道秘密。

现在我们需要确保令牌只能使用一次。

rnd = rand()
token = rnd + hash(session_id + secret + rnd)

令牌现在有一个随机数。发生POST时,我们可以将此随机数存储为“之前已使用过”,并拒绝重新使用相同随机数的任何令牌。

但我们不想永久存储使用过的令牌的随机数。所以我们限制了令牌的生命周期。

rnd = rand()
now = time()
token = rnd + time + hash(session_id + secret + rnd + time)

在POST时,当我们获得令牌时,我们现在检查是否“最近”发出了令牌。我们只需要为相同的时间跨度存储使用过的随机数。根据定义,所有旧令牌都无效。

您可以保护使用的随机数以及会话ID,并在您逐出会话ID或将其变为无效时删除它们(以先发生者为准)。

答案 1 :(得分:1)

我会独立实现这些功能:

CSRF预防

使用CSRF令牌阻止成功的CSRF攻击:为每个会话或每个URL /表单生成随机令牌,并将其存储在会话中。最初请求表单时,请放置(关联的)CSRF令牌,并在处理提交的表单数据时对其进行验证。

由于CSRF令牌由服务器生成并存储在服务器上,因此攻击站点不能伪造它,并且仅对该会话有效。同样,验证也是微不足道的。唯一剩下的风险是攻击站点可以通过跨站点脚本获取已发布的CSRF令牌(但这会使CSRF在某种程度上过时)。

多表单提交预防

使用一次有效的令牌来阻止多次提交:为每个初始表单请求生成唯一标记并将其放在表单中。在表单提交时,检查该令牌是否已被使用并将其记住为已使用。

要仅允许服务器发布的令牌,您可以使用某种message authentication algorithm。要降低要记住的令牌数量,您可以让令牌在某个时间到期,这样您就必须记住特定时间范围内的令牌。

多个标签页或表单请求都没有问题:CSRF标记在整个会话期间或对特定URL /表单的任何表单提交都有效。另一个令牌仅对单个表单提交有效。