如何在 NodeJS 中使用生成的随机数并在不调用数据库的情况下进行验证?

How to use a generated nonce in NodeJS and do validation without a database call?

我正在生成随机数来验证向导步骤以一个接一个地保护它。

我知道如何在 nodejs 中创建随机数并将其存储在数据库中以确保它可以使用一次。

但我想知道,是否有一个想法来生成和验证上面的随机数,就像只使用一次,如果可能的话,可以在一个时间限制(到期)内使用而不将其存储在数据库中但只需在一个向导步骤中将其返回给客户端,并在下一步中对其进行验证。

我通常使用下面的方法生成随机数,将其规范化并将其存储在 mongodb 中,并且有一个到期时间,这样 mongodb 将在特定时间后删除它,如果它不是已使用。

var crypto = require('crypto');

crypto.randomBytes(32, function (err, bytes) {
   if (err) {
       next(err);
    } else {
       next(null, normalize(bytes));
    }
});

如果有任何 good/optimized 生成 nonce 的方法以及无需数据库调用即可处理一次性使用和过期的可能性,请提出建议。

最好有一个数据库来存储和验证 nonce。要限制时间,您可以使用带有到期时间的 mongodb 或者您可以生成时间戳,然后生成带有时间戳、随机数和私钥的 hmac。然后将随机数、时间戳和 hmac 发送给客户端。通过这种方式,您还可以保护时间戳,如果您的数据库不支持文档过期 mongodb,则您可以限制特定时间的随机数。希望解释清楚。

有可能在没有数据库调用的情况下有一个过期的随机数,使用服务器上的哈希映射之类的东西来存储和检索随机数并检查时间。如果有会话 ID 或静态用户 ID,那将有所帮助。然而,与 MongoDB 等经过测试的解决方案相比,让服务器生成、保存、获取和维护随机数的想法似乎很困难。如果一个服务有多个服务器,则会发生另一个问题,在会话开始到结束时,流量必须保持一致。使用数据库作为 nonce 的单一真实来源可以解决这个问题。

如果将随机数保留在节点服务器上的原因是为了速度/延迟,那么额外的测试和代码可能是值得的。在那种情况下,需要定期扫描 nonce 的超时以查找过期的 nonce,以保持快速搜索。

编辑:这个答案不能防止重放攻击,为此你需要数据库。

The reason for storing a nonce is to ensure that it can only be used once. This protects against reply attacks, where a malicious party could potentially intercept a valid request and then retransmit it. The extra step of validating the nonce prevents the replayed request from being accepted.

To prevent certain types of 'replay' attack, it is important to know not only that the nonce is unique but that it has not been used in a previous request. Real world example: A bank issues a chequebook, where each cheque has a unique number. If I write you a check and sign it you can then take it to the bank and get the money. The bank needs to record the number of every check that has been cashed, otherwise you could simply photocopy the original check I gave you and claim that money again

旧答案(我没有删除它,因为它在数学上很优雅:)

如果您使用 128 位的加密随机数,您有 2^(128) 个数字的可能性。考虑一个均匀分布的随机数生成器,并且你每秒调用一次这样的函数,重复的概率几乎为零。

你可以在node中使用类似的东西(这里转换为base64

const crypto = require('crypto');
var nonce = crypto.randomBytes(16).toString('base64');

128 位是 16 个字节。

数学演示

适用的二项分布的概率质量函数为

这个函数 returns 在 n 次试验中获得恰好 [=7​​5=]k 次成功的概率,p 是每次试验的成功概率。

在我们的案例中 p=1/(2^128)

累积函数为

其中总和上的 k 是 k 下的“floor”,即小于或等于 k ​​的最大整数。这个累积函数给出了成功次数介于 0 和 k.

之间的概率

但我们需要至少一次成功试验的概率,因为我们不想重复。考虑到

因此

这意味着 k=1

在我们的例子中,如果我们在 100 年内每秒调用一次随机数 ,我们会得到 n=1*60*60*24*365.25*100=3155760000

因此

p=1/(2^128);
n=3155760000;

应用公式

结论

如果你使用128位的nonce并且你在100年内每秒调用一次nonce,那么在这100年期间重复该nonce的概率几乎为零,这意味着几乎不可能。这意味着您不需要数据库。