为啥 Express/Connect 会在每个请求上生成新的 CSRF 令牌?

Posted

技术标签:

【中文标题】为啥 Express/Connect 会在每个请求上生成新的 CSRF 令牌?【英文标题】:Why does Express/Connect generate new CSRF token on each request?为什么 Express/Connect 会在每个请求上生成新的 CSRF 令牌? 【发布时间】:2014-03-05 21:54:38 【问题描述】:

据我了解,有两种方法可以防止 CSRF 攻击:1) 每个会话的令牌,以及 2) 每个请求的令牌

1) 在第一种情况下,CSRF 令牌仅在用户会话初始化时生成一次。因此,用户一次只有一个有效令牌。

2) 在第二种情况下,每个请求都会生成新的 CSRF 令牌,然后旧的令牌变得无效。 漏洞利用变得更加困难,因为即使攻击者窃取了令牌(通过 XSS)当用户转到下一页时它也会过期。 但另一方面,这种方法会降低 webapp 的可用性。这是来自security.stackexchange.com的一个很好的引用:

例如,如果他们点击“返回”按钮并使用新值提交表单,则提交将失败,并且可能会以一些恶意错误消息迎接他们。如果他们尝试在第二个选项卡中打开资源,他们会发现会话在一个或两个选项卡中随机中断

在分析 Node.js Express 框架(基于 Connect)时,我注意到每个请求都会生成一个新的 CSRF 令牌, 但旧的不会失效

我的问题是:在每个请求上提供新的 CSRF 令牌而不是使旧的无效的原因是什么? 为什么不只为每个会话生成一个令牌?

谢谢你,对不起我的英语!

【问题讨论】:

【参考方案1】:

CSRF 令牌是随机数。它们应该只使用一次(或在很长一段时间后安全使用)。它们用于识别和授权请求。让我们考虑两种预防 CSRF 的方法:

    每个会话固定一个令牌:这样做的缺点是客户端可以将其令牌传递给其他人。这可能不是由于嗅探或中间人或某些安全漏洞。这是对用户的背叛。多个客户端可以使用相同的令牌。遗憾的是,对此无能为力。

    动态令牌:每当服务器和客户端之间发生任何交互或发生超时时,都会更新令牌。它可以防止多个客户端同时使用旧令牌。

动态令牌的缺点是它限制了从那里返回和继续。在某些情况下,它可能是可取的,例如在实施购物车时,必须重新加载以检查是否有库存。 CSRF 将防止重新发送已发送的表单或重复购买/出售。

细粒度的控制会更好。对于您提到的场景,您可以在没有 CSRF 验证的情况下进行。然后不要对该特定页面使用 CSRF。换句话说,处理每个路由的 CSRF(或其异常)。

更新

我只能想到单个动态令牌优于多个的两个原因:

    多个令牌确实更好,但至少有一个像上面那样的动态令牌。这意味着设计一个可能变得复杂的详细工作流程。例如看这里:

      https://developers.google.com/accounts/docs/OAuth2 https://dev.twitter.com/docs/auth/implementing-sign-twitter https://developers.facebook.com/docs/facebook-login/access-tokens/

    这些是访问其 API(表单提交等)的令牌,而不仅仅是登录。每个人都以不同的方式实现它们。除非有好的用例,否则不值得做。您的网页将大量使用它。更何况现在提交表单已经不简单了。

    动态单个令牌是最简单的,并且在库中很容易获得。所以可以在旅途中使用它。

多代币的优势:

    可以实现事务。您可以在请求之间进行排序。 可以从超时和身份验证错误中回退(您现在必须处理它们)。 安全!比单个令牌更健壮。可以检测令牌滥用、黑名单用户。

顺便说一句,如果您想使用多个令牌,您现在拥有 OAuth2 库。

【讨论】:

感谢您的回答,非常感谢。但它没有描述多个有效令牌比单个有效令牌有什么优势。

以上是关于为啥 Express/Connect 会在每个请求上生成新的 CSRF 令牌?的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使未启用 CORS,HTTP 请求也会在 Action 中处理? [复制]

Connect/Express 中的“session”和“cookieSession”中间件有啥区别?

安装svn后 为啥会在每个目录下出现一个.svn的文件

为啥刷新令牌会在 14 天后过期

为啥偶尔会在 ListView 中加载错误的图像?

为啥 GAE 上的 Restlet 说 Component 是 NULL