CSRF令牌与Nonce混淆-它们是相同的吗?

23

为了使我正在开发的应用程序更加安全,我一直在阅读有关CSRF令牌和Nonce的内容。

我的问题很简单,CSRF令牌和Nonce是相同的吗?据我目前所了解的,这两种方法具有不同的技术来实现相同的目标,或者我有什么误解吗?

如果它们是不同的,请您提供一些示例代码或指向一些链接,让我了解如何在PHP应用程序中实现随机数。谢谢!

4个回答

24
不,它们不一样。
Nonce可防止重放攻击(例如,如果Alice发送“Pay Bob $100”,则不希望有人将其存储并稍后重新提交签名请求)。
CSRF令牌修补了用户操作验证中的HTML特定弱点,其中第三方网站可以使用查看该站点的用户的凭据提交表单(例如,来自evil.example.com的JavaScript使用您的浏览器向facebook.com提交表单,作为您进行身份验证)。
如果CSRF令牌不保密,则攻击者将具备伪造请求所需的缺失部分的能力。
如果使用请求者的密钥签名nonce,则nonce不必保密(只要攻击者无法用另一个nonce替换一个nonce)。
您可以允许通过CSRF令牌重播请求并仍然受到CSRF保护(您感兴趣的是用户是否故意执行此操作,但可能不一定想阻止用户多次执行此操作)。
事实上,这是非常有用的属性,例如允许用户使用后退按钮并重新提交带有更正值的表单。如果您使用类似nonce的机制实现CSRF保护,则在用户刷新已提交页面时会出现误报警报。
一种无需Nonce即可防止CSRF的简单方法是将会话ID放入隐藏的表单字段中(不是存储在会话中的值,而是会话本身的ID,与在cookie中存储的相同[在PHP中为session_id()])。提交表单时,请检查表单的会话ID是否与cookie中的ID匹配。这对于CSRF足够了,因为攻击者无法知道cookie的值(CSRF仅允许攻击者盲目发送cookie)。

1
不应该使用标识符(如会话ID)作为CSRF令牌,这会允许攻击者通过请求将页面保存为HTML,并嵌入仍然有效的会话ID来欺骗受害者。 - Dalibor Karlović

19

Nonce通常是一些随机字符串,添加到请求中只是为了以不可预测的方式更改用于计算签名的数据。因此,Nonce通常不由任何服务器端业务逻辑使用。

而CSRF-token存储在服务器的某个位置上,传递给客户端并需要返回到服务器进行比较。如果匹配,则OK。

因此,在您的情况下,更好的方法是将Csrf令牌保存在会话变量中:

$_SESSION['csrf_token'] = bin2hex(random_bytes(16));

在您的应用程序中,在会话生命周期内以所有形式不加修改地使用它。

(如果您没有random_bytes(),请使用random_compat进行兼容性填充。)


嗯...我记得在某个地方看到人们将nonce值存储在数据库表中?目前,我为每个新表单定义form_tokens,而不仅仅是“一个”,因此每次用户使用表单脚本时,都会通过csrf令牌传递它,这种做法是否正确? - Zubair1
1
@Zubair1:我认为这是过度工程化的,可能会给用户和开发者带来一些麻烦:现在你需要同时存储许多令牌,否则访问者无法从不同的标签页中发布表单... 一个令牌并不更安全,但要方便得多。至于随机数 - 我在现实生活中从未见过。 - zerkms
@zerkms:谢谢,这是一个好观点,只分配一次csrf_token肯定更容易维护。我应该在用户成功登录后设置csrf_token吗?并且在用户注销时销毁该csrf_token?但是那么我应该在什么时候验证csrf_token呢?在表单提交时?我也对Nonce感兴趣,但是现在实施它似乎对我来说更加复杂,因为我不太理解如何将其正确地引入应用程序中。 - Zubair1
1
@Zubair1: 实现一个函数getCsrfToken(),在需要时返回一个值,并且按需创建(存储在会话中),仅在需要时创建。无需担心删除它。关于nonce:我只知道如何在API中使用nonce,在与用户(浏览器)和服务器的常规互联场景中不适用。 - zerkms
1
@Zubair1:1.你把它放在每个表单的隐藏域中 2.在处理表单之前 - 你比较 if($_POST['csrf_token'] == getToken())。如果是真的 - 那么一切正常。 - zerkms
显示剩余12条评论

10

这其实是同一件事情。"Nonce"仅仅是一个一次性的密码本身,可以作为加密盐使用,但基本上只是随机值。请参见WP:Nonce

简单来说,Nonce通常被用作CSRF令牌。它是一种实现细节。与其他用例的区别在于,它稍后会被断言。


0

CSRF 有一些限制。 如果您有需要在新标签页中打开任何页面或链接的要求,则 CSRF 不允许。现有令牌仅允许在新标签页中打开页面 5 次。 当您尝试第 6 次打开时,它将创建一个新令牌,该令牌将与“服务器端=客户端令牌”不匹配。早期令牌将过期,并将创建新令牌(NONCE),在这种情况下,您将收到 404 或 405 错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接