我最近的任务是创建一个定制的OAuth登录和注册流程.因此,我很好奇为OAuth请求生成和存储CSRF令牌的最佳方式是什么.我已经读过几篇关于这方面的文章,其中一篇来自Auth0.他们指出,CSRF令牌(随机字符串)应该放在对OAuth提供者的请求中,然后存储在本地.然后,当命中回调URL时,可以将状态为令牌的令牌与本地存储的令牌进行核对,以查看请求是否有效.

于是,我读了下面这篇来自Bright Sec的文章.它规定,

就像一般的会话令牌一样,CSRF令牌应该包含显著的熵,并且具有很强的不可预测性.

您可以通过使用加密强度伪随机数生成器(PRNG)来实现这一点,该生成器带有创建时的时间戳和静态秘密.

这意味着它们应该比Auth0文章中的随机字符串多一点.因此,像UUID这样的东西(这是我最初的 idea )可能并不真正符合良好的CSRF令牌的标准.

另外,我看到的这些文章大多是关于提交表格的.

So my question is what is the best way to create a csrf token in nodejs and where should I store it locally when authenticating to providers like Google and Facebook?

My current understanding of what should happen.

  1. 用户启动身份验证请求,此时您将创建一个CSRF令牌(仍然不确定执行此操作的最佳方法),并将其保存到本地(可能保存到会话中?).
  2. 将此令牌发送到状态参数中的OAuth提供程序
  3. 当OAuth提供程序响应您的回调url时,它们将在状态参数中将令牌发送回您,您应该比较2以确保请求是可信的.

有针对NodeJS的CRSF库.主要是Express中间件,但我不太确定这是否适用于OAuth请求.我一直试图梳理Passportjs和Next-auth,看看他们的方法是什么,但我认为这让我更困惑.Next Auth似乎将CSRF令牌作为Cookie存储在浏览器中,如下图所示:

Cookie image

因此,我只能假设CSRF令牌基本上只是为了确保如果有人拦截来自OAuth提供程序的请求返回到原始回调URL,他们不能从他们的浏览器使用它.因此,csrf令牌只是为了确保命中回调URL的请求是从它启动的同一个浏览器发起的.对,是这样?

无论如何,如果有任何关于如何创建令牌以及我应该将其存储在哪里的帮助,我将不胜感激.

推荐答案

我认为了解可能的攻击是如何发生的是有益的,以便了解CSRF如何潜在地提供帮助.

用户启动身份验证请求,此时您将创建一个CSRF令牌(仍然不确定执行此操作的最佳方法),并将其保存到本地(可能保存到会话中?). 将此令牌发送到状态参数中的OAuth提供程序 当OAuth提供程序响应您的回调url时,它们将在状态参数中将令牌发送回您,您应该比较2以确保请求是可信的.

是的,你在这一点上是正确的.如果这里没有CSRF,恶意攻击者只需捕获URL并让第三方访问该URL,他们就能够访问他们的帐户.

您可以通过使用恶意行为者无法猜测的东西来创建随机状态值来防止这种情况发生,例如标记为UserID的会话密钥.

没有标准化的方法来存储这个密钥.您还可以使用基于TOTP的解决方案,如果OAuth2流返回的时间太长,您可以使用该解决方案使令牌无效.这允许您只存储用于生成标记到某个用户标识符的密钥的临时秘密,您只需将其存储在服务器端的Redis缓存中.这样,在验证步骤中,您只需要根据存储的临时密钥重新创建CSRF并进行验证.

因此,现在启动您提到的正常OAuth2流,然后比较令牌以进行验证.

我希望这能有所帮助,其他专家也能加入进来.我是在手机上写的,所以请原谅任何格式问题.

Node.js相关问答推荐

如何在node.js中以随机顺序调用函数并按顺序操作

如何使用多个OR参数从多个集合聚合

Sequelize-测试使用虚拟场更新模型

MongoDB如果文档S的字段小于另一个字段,则将该字段加一

我收到警告:发现函数rs-ms-v1不受支持的运行时nodejs18.x× 不受支持的运行时

无法从 mongoDB 访问数据?

密码加密的最佳实践是什么?

如何在 Docker 容器中 SSO 登录 AWS(使用 aws-sdk v3)

MongoDB Aggregate - 如何使用前一阶段的值作为下一阶段的字段名称?

将 AllowDiskUse true 添加到 node.js 中的 MongoDB 聚合?

ESLint:TypeError:this.libOptions.parse 不是函数

在 NodeJS/ESP32 中通过 WebSocket 发送二进制数据 - 如何识别二进制和文本消息

aws cdk 2.0 init 应用程序无法构建更漂亮的问题,这来自 jest-snapshot

`npm install` 以Killed结尾

Node.js + Express + Handlebars.js + 局部视图

如何使用 mocha.js 模拟用于单元测试的依赖类?

我可以有条件地将 where() 子句添加到我的 knex 查询吗?

node.js 中存储的模块变量在什么范围内?

在单独的模块中定义 Mongoose 模型

找不到在 docker compose 环境中运行的 node js 应用程序的模块