CSRF令牌生成

这是关于生成CSRF令牌的问题。

通常我想根据与用户会话相关的独特数据生成令牌,并使用密钥进行哈希和腌制。

我的问题是在没有唯一的用户数据使用时生成令牌。 没有会议可用,cookies不是一个选项,IP地址和这种性质的东西是不可靠的。

是否有任何理由不能将string作为请求的一部分join? 示例伪代码来生成令牌并embedded它:

var $stringToHash = random() var $csrfToken = hash($stringToHash + $mySecretKey) <a href="http://foo.com?csrfToken={$csrfToken}&key={$stringToHash}">click me</a> 

CSRF令牌的示例服务器端validation

 var $stringToHash = request.get('key') var $isValidToken = hash($stringToHash + $mySecrtKey) == request.get('csrfToken') 

在散列中使用的string将在每个请求上不同。 只要包含在每个请求中,就可以继续进行CSRF令牌validation。 由于每个请求都是新的,只有embedded到页面中,所以不能访问令牌。 令牌的安全性然后下降到我知道的$ mySecretKey。

这是一个天真的方法? 我错过了一些原因,为什么这不能工作?

谢谢

是否有任何理由不能将string作为请求的一部分join?

CSRF令牌有两个部分。 embedded到表单中的令牌和其他地方的相应令牌,可以放在cookie中,存储在会话中或其他地方。 在其他地方的这种使用停止了页面被包含。

如果在请求中包含string哈希,那么请求是自包含的,因此复制表单是攻击者需要做的,因为它们都具有令牌的两个部分,因此没有保护。

即使将它放在表单URL中也意味着它是自包含的,攻击者只需复制表单和提交URL即可。

CSRF令牌旨在防止(无意的)数据修改,通常与POST请求一起应用。

因此,您必须为每个更改数据的请求(GET或POST请求)包含CSRF令牌。

我的问题是在没有唯一的用户数据使用时生成令牌。 没有会议可用,cookies不是一个选项,IP地址和这种性质的东西是不可靠的。

然后只需为每个访客创build一个唯一的用户ID。 将该ID包含在Cookie中或URL中(如果Cookie被禁用)。

编辑:

考虑以下事件:

你已经login到你的Facebook帐户,然后进入一些任意的网站。

在那个网站上有一个表单,你提交,它告诉你的浏览器发送POST请求到你的Facebook帐户。

该POST请求可能会更改您的密码或添加评论等,因为Facebook应用程序将您识别为已注册和已login的用户。 (除非另有阻止机制,如validation码)

你只需要在URL /表单和cookie中需要相同的“标记”。 这意味着你可以让你的页面通过JavaScript设置令牌cookie到任何想要的(最好是一些随机值),然后在所有请求中传递给你的服务器的相同的值(作为URI?param或form-领域)。 没有必要让你的服务器生成cookie。

只要我们相信浏览器不允许来自域的页面编辑/读取其他域的cookie,这是安全的,而且今天这个假设是相当安全的。

让您的服务器生成令牌将假定这个令牌可以安全地传输到您的浏览器,而不会被任何CSRF尝试(为什么冒险?)拾取。 尽pipe可以将更多逻辑放入服务器生成的令牌中,但是为了防止CSRF,不需要这么做。

(如果我错了,请让我知道)

我认为最好的做法是基于HMAC制作散列,即使用一些密码encryptionhash序列:username + user_id + timestamp。 每个哈希请求必须不同,时间戳必须是,如果你不想简单地重播攻击哈希。

我想说你的方法是有效的,因为CSRF攻击是利用受害者浏览器伪造login状态的攻击者,他们为什么要这样做? 因为在大多数服务器端会话检查是基于Cookie中的SessionID,而Cookie是一段数据将被自动附加到发送给服务器的HTTP请求。

因此,防守CSRF有两个关键因素

  1. 生成一个质询令牌,并要求客户端以非Cookie方式将其传递给服务器,URL参数或POSTforms都可以。
  2. 像令牌一样保持令牌安全,例如使用SSL。

我build议阅读CSRF预防备忘单

CSRF利用用户的会话,所以,如果你没有,会没有CSRF。