我正在尝试使用没有状态的 node.js 服务器实现一种电子邮件验证系统。
战略
- 用户将他的电子邮件发送到服务器
- 服务器根据电子邮件地址生成一个 4 位代码,并通过电子邮件将其发送给用户。
- 用户通过电子邮件+电子邮件地址将收到的代码发送回服务器
- 服务器根据电子邮件重新生成 4 位代码,并将其与用户发送的代码进行比较。
我生成 4 位数代码的实现
- 使用 HMAC SHA-256 哈希函数创建 HEX 摘要
- 取摘要的前 3 个字符
- 将它们转换为整数
- 如果长度 < 4,
0则在末尾连接一个或多个
const crypto = require('crypto')
const get4DigitsCode = (message) => {
const hash = crypto
.createHmac('sha256', Buffer.from(SECRET_KEY, 'hex'))
.update(message)
.digest('hex')
const first3HexCharacters = hash.slice(0, 3)
const int = parseInt(first3HexCharacters, 16)
let code = int.toString()
code =
Array(4 - code.length)
.fill(0)
.join("") + code
return code
}
在为 8293 个电子邮件地址生成代码后,我注意到我有 4758 个重复项。像这种类型的代码有这么多重复是否正常?我的策略和我的实施是否安全(猜测代码的能力)?
该服务是一个移动应用程序,基于电子邮件(“给自己的邮件”应用程序)。出于用户体验的原因,我想要一个 4 位数的代码。用户可以从电子邮件客户端通知中读取代码,轻松记住并在应用程序中输入(他永远不会离开)。无需繁琐的复制和粘贴,无需离开应用程序,只需阅读和输入即可。我知道多封电子邮件会生成相同的代码,但这并不重要,因为它只是用于验证电子邮件。我还将保护 API 免受暴力破解。
有人可以用这种策略猜出代码(有什么风险或可能的攻击?),我目前的实现是否正确?
更新
感谢@duskwuff的回答,一个更好的实现:
const crypto = require('crypto')
const get4DigitsCode = (message) => {
const hash = crypto
.createHmac('sha256', Buffer.from(SECRET, 'hex'))
.update(message)
.digest('hex');
const first4HexCharacters = hash.slice(0, 4);
const int = parseInt(first4HexCharacters, 16) % 10000;
let code = int.toString();
code =
Array(4 - code.length)
.fill(0)
.join('') + code;
return code;
};