我见过几个 CSRF 令牌的实现:
- 第一个使用随机生成的 CSRF 令牌,它使用加密强随机生成器来生成令牌。
- 我发现的第二个实现使用 HMAC,它使用存储在服务器端配置中的密钥加密会话 ID。
- 我看到的第三个实现使用了两者的组合,存储在服务器端配置中的密钥用于 HMAC 随机生成的值
第二个不需要将状态存储在服务器端(这在集群的情况下是理想的)。
我想知道第一个和第三个实现之间有什么好处。
我见过几个 CSRF 令牌的实现:
第二个不需要将状态存储在服务器端(这在集群的情况下是理想的)。
我想知道第一个和第三个实现之间有什么好处。
第一个使用随机生成的 CSRF 令牌,它使用加密强随机生成器来生成令牌。
这是理想的。在这种情况下,令牌是一个绝对不可预测的不透明块,在其预期上下文之外没有任何意义。
我发现的第二个实现使用 HMAC,它使用存储在服务器端配置中的密钥加密会话 ID。
这更容易实现。大概会话 ID 已经生成,因此不需要保留任何其他内容。由于不需要进一步的存储,因此这种机制可能可以在随机令牌无法用于遗留设计的情况下实现。这是一个相对优雅的解决方法。假设攻击者不知道密钥,则令牌不应该在服务器之外重现。
我看到的第三个实现使用了两者的组合,存储在服务器端配置中的密钥用于 HMAC 随机生成的值
这有点傻。大概是由于 HMAC 是一个与安全相关的概念这一事实,作者试图通过包含一些与安全相关的东西来为他的设计添加安全性。一种神奇的安全护身符。大概它并不比单独使用随机数差,但肯定也好不到哪里去。除非您计算在安全实施中使用 HMAC 所带来的温暖模糊感。
但是,如果您的 RNG 很差,这是一个合理的解决方法,但在这种情况下,我可能会在散列之前混合会话 ID 或类似的东西,以保证您散列的数字是唯一的。
我知道 asp.net MVC 3/4 使用类似于 2 的方法。我发现这种方法的问题是会话有一个 CSRF 令牌,而不是表单。例如,如果我获得一次 CSRF 令牌,则该令牌对会话期间的任何表单发布都有效。使用 ZAP 之类的工具进行测试时,一个请求会给我一个令牌,然后我可以随意重用它。此外,令牌必须写入 HTML 页面的某个位置(例如,它不存储在 cookie 中),然后攻击者可以轻松读取该令牌以查找特定字符串。
我喜欢1/3的想法。随机性基于表单/调用提供安全性,而不是每个会话一个。它还可以用于防止相同形式的多个帖子。这在您希望确保提交只发生一次的事务系统中非常有用。当服务器收到第一次提交时,它会使令牌失效。下一次提交将失败。攻击者现在必须在用户之前获得一个令牌并使用它。
我可以看到您关于集群/负载平衡的观点,但大多数负载平衡器可以/将来自同一会话的请求转发到同一后端主机。
对于正确的无状态系统,您可以执行以下操作。生成 arandomString
和hmac
它与 a secret
。所以你的 CSRF 令牌是这样的*:
token = "{timestamp} {randomString} {hmac(secret, timestamp + randomstring)}"
现在在服务器端,您从令牌中提取timestamp
并使用秘密,并验证它是由持有.randomString
hmac
secret
所以我相信选项 3 是唯一真正无状态的选项。
如果您有会话 ID,则可以使用选项 2。
*timestamp
添加到token
andhmac
用于验证令牌的年龄。
更新!
这似乎毫无意义。黑客可以访问该网站,获取合法hmaced
令牌并使用它。所以这并不比随机生成的令牌更好(只是看起来更漂亮)。因此,对于hmaced
令牌,您需要一些用户可识别信息,例如sessionId
或userId
。
向所有表单添加哈希(会话 ID、函数名称、服务器端密码)。