10

为了防止 CSRF,您应该在表单的隐藏字段中、cookie 或会话变量中放置一个 nonce。但是,如果用户在不同的选项卡中打开多个页面怎么办?在这种情况下,每个选项卡都会有一个具有唯一 nonce 的表单,但会话变量或 cookie 中只会存储一个 nonce。或者,如果您尝试将所有 nonce 存储在 cookie/session 变量中,您将如何识别哪个属于哪种形式?

4

4 回答 4

7

您可以在每个表单中存储相同的随机数。最简单的方法是将 nonce 绑定到会话 ID,以便这些表单仅在该会话中有效。

您将希望让攻击者难以窃取会话 ID 并创建自己的随机数。因此,一种解决方法是使用 HMAC-SHA256(或类似方法)对会话 ID 进行哈希处理,使用您不向公众公开的密钥。

(很明显,如果攻击者可以自己获取实际的会话 ID,他们就已经可以进行会话劫持了。所以这不是我要说的,而是攻击者制作脚本(在受害者的计算机上运行)的能力。可以以某种方式获取会话 ID 并使用它来动态生成预先填充随机数的 URL。)


ETA:上述方法本身是否足够取决于您期望您的典型会话持续多长时间。如果用户通常使用超过几个小时的持久会话,则您需要使用更复杂的东西。

一种方法是为每个表单创建一个新的 nonce,其中包含时间戳以及hash(timestamp . sessionid)(其中hash是如上所述的 HMAC 的一些变体,以防止伪造,并且.是字符串连接)。然后,您通过以下方式验证随机数:

  1. 检查时间戳以确保 nonce 足够新鲜(这取决于您的策略,但通常需要几个小时)
  2. 然后,根据时间戳和会话 ID 计算哈希,并与 nonce 进行比较,以验证 nonce 是真实的

如果随机数检查失败,您还需要显示一个新表单,其中预先填充了用户提交的内容(这样如果他们花了一整天的时间来写他们的帖子,他们也不会失去所有的辛勤工作)作为一个新鲜的随机数。然后用户可以立即成功重新提交。

于 2010-02-12T07:43:48.133 回答
3

有些人确实为每个表单生成一个令牌,这是一种非常安全的方法。但是,这可能会破坏您的应用程序并激怒用户。为了防止所有 XSRF 针对您的站点,您只需要每个会话唯一的 1 个令牌变量,然后攻击者将无法伪造任何请求,除非他能找到这 1 个令牌。这种方法的一个小问题是,只要受害者正在访问攻击者控制的网站,攻击者就可以暴力破解这个令牌。但是,如果令牌非常大,例如 32 个字节左右,那么暴力破解需要很多年,并且 http 会话应该在此之前很久就过期。

于 2010-02-12T20:04:03.870 回答
3

您所描述的不再是 nonce(nonce = number used once),它只是一个会话标识符。nonce 的全部意义在于它仅对单个表单提交有效,因此提供了比仅会话 ID 更高的安全性来防止劫持,但代价是无法在站点上并行运行多个选项卡。

随机数对于许多目的来说都是多余的。如果您使用它们,您应该只在对系统进行关键更改的表单上设置和要求它们,并教育用户他们不能期望并行使用多个这样的表单。未设置 nonce 的页面应注意不要从会话中清除任何先前存储的 nonce,以便用户仍然可以与 nonced 表单并行使用 non-nonced 页面。

于 2013-10-23T22:53:14.703 回答
0

很久以前写过这篇文章。我已经实现了一个我几乎可以肯定可以很好地保护的 csrf 阻止程序。它确实适用于多个打开的窗口,但我仍在评估它提供的保护类型。它使用数据库方法,即存储而不是会话到表。注意:在这种情况下,我使用 MD5 作为一种简单的反sqli 机制

伪代码:

形式:

token = randomstring #to be used in form hidden input
db->insert into csrf (token, user_id) values (md5(token),md5(cookie(user_id))

-- 然后将令牌保存在数据库中,直到从下面的操作脚本中访问它:

动作脚本:

if md5(post(token)) belongs to md5(cookie(user_id)) 
    #discard the token
    db -> delete from csrf where token=md5(post(token)) and user_id=md5(cookie(user_id)) 
    do the rest of the stuff
于 2013-09-10T22:42:50.253 回答