CSRF令牌与Nonce的混淆——它们是一样的吗?


CSRF tokens vs Nonce confusion - are they the same?

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

我的问题是,CSRF令牌和Nonce是一回事吗?到目前为止,我能收集到的是,这两种方法都有不同的技术来实现相同的目标,还是我误解了什么?

如果它们是不同的,你可以很好地提供一些示例代码或指向我一些链接,在那里我可以了解更多关于如何在PHP应用程序中实现nonce。

谢谢!

不,它们不一样。

Nonces防止重放攻击(防止窃听者存储签名请求并在以后重新提交它,例如,如果Alice发送"支付Bob 100美元",你不希望有人重新发送100次)。

CSRF令牌修补了用户行为认证中html特定的弱点,其中第三方网站可以提交带有用户查看网站凭据的表单(例如evil.example.com上的JavaScript使用您的浏览器向facebook.com提交表单,身份验证为您)。

CSRF令牌需要保密,否则攻击者将拥有伪造请求所需的缺失部分。

nonce不必是秘密的,如果它们是用请求者的秘密签名的(只要攻击者不能用另一个代替一个nonce)。

您可以允许使用CSRF令牌重放请求,并且仍然可以防止CSRF(您感兴趣的是这是否是用户有意的操作,但可能不一定要阻止用户多次执行)。

事实上,这是一个非常有用的属性,例如,允许用户使用后退按钮并重新提交带有正确值的表单。如果您使用Nonce-like机制实现CSRF保护,当用户刷新提交的页面时,您将获得假警报。 防止CSRF没有Nonces的一个简单方法是将会话ID放在一个hidden from字段中(不是在会话中存储的值,而是会话本身的ID,与存储在cookie [PHP中的session_id()]中的ID相同)。提交表单时,检查表单的会话ID是否与cookie中的ID匹配。这对CSRF来说已经足够了,因为攻击者无法知道cookie的 (CSRF只允许攻击者盲目发送cookie)。

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

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

所以在你的情况下,最好将csrf令牌保存一次在会话变量中,如
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));

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

(如果你没有random_bytes(),使用random_compat填充它)

这是一样的。"nonce"本身只是一个一次性密码。它可以作为加密盐,但基本上只是一个随机值。看到WP: Nonce

但总的来说,nonce通常被用作 CSRF令牌。这是一个实现细节。与其他用例的不同之处在于它稍后被断言。

CSRF有一些限制。在情况下,如果你有要求,你想在新标签打开任何页面或链接,那么CSRF将不允许。现有的标记只允许在新选项卡中打开页面5次。当您尝试打开第六次时,它将创建与"服务器端=客户端令牌"不匹配的新令牌。较早的令牌将过期,新令牌(NONCE)将创建,在这种情况下,您将得到404或405错误。