哈希与数据库查找效率

Hashing vs Database Lookup Efficiency

我打算使用哈希生成验证令牌来验证电子邮件地址。哈希将像这样生成:

email:username:salt

哈希是使用 SHA256 算法生成的,并且对生成的每个令牌使用相同的盐。

另一种更常用的方法是生成一次性 UID,该 UID 存储在数据库中并用作新电子邮件地址的验证。

我的问题是:这是一种有效的(考虑处理器和磁盘利用率等)实现电子邮件验证令牌生成的方法吗?

电子邮件验证令牌的全部目的是从您的安全网络服务器生成令牌,并将该令牌通过电子邮件发送给某人,以便他们可以单击包含该令牌的 link,这样您就可以验证他们的帐户。

需要牢记的重要事项:

  • 令牌必须是最终用户无法复制的,否则可能是伪造的。
  • 令牌需要由您的网络服务器进行加密签名(理想情况下),以便客户端知道这是一个有效的令牌。这也很重要,因为当用户将此令牌发送回您的服务器时,您可以验证您的服务器是创建它的服务器。
  • 令牌需要过期:如果在一定时间内未使用,您应该能够'expire'此令牌:24 小时、3 天等

因此,我不推荐您采用的方法。

相反,我会使用 JSON web token (this is an ideal use case for them). This other SO question 有一个不错的摘要。

使用 JWT 将使您:

  • 在您的网络服务器上创建令牌。
  • 为此令牌设置一个 'expirey' 日期,以便在您指定的特定时间限制后无法使用它。
  • 在您想要的令牌中对任何特定于用户的数据进行编码:通常是用户 ID 或类似的东西。

当用户将令牌发送回您的网络服务器时,JWT 将:

  • 保证令牌是由您的服务器生成的,而不是其他人恶意生成的。
  • 保证令牌仍然有效(时间戳)。
  • 保证令牌未被篡改。
  • 让您查看之前编码的令牌数据(用户 ID / 等)。

希望对您有所帮助 =)

你正在做的事情有点安全。

虽然我将您的盐称为密钥 - 您正在生成密钥散列。确保您生成的密钥具有足够的熵。我建议使用 CSPRNG 生成的 128 位强度。

以这种方式生成的一些键控哈希容易受到长度扩展攻击。也就是说,如果攻击者为 foo@example.com 生成了验证令牌,那么他们将能够计算出 foo@example.com.example.org 的哈希值。这是因为哈希算法的输出也背叛了它的状态。为了缓解这种情况,您可以使用 HMAC algorithm.

您当前的方法还有一个限制,即电子邮件地址始终具有相同的令牌。如果电子邮件地址过期(例如,电子邮件地址为 bobs@example.org 的 Bob Smith 被 Example Organization 解雇,他将知道下一个 Bob S. 开始为 Example Organization 工作时将获得的验证码)。这是否会对您的应用程序构成任何风险由您决定。为了缓解这种情况,您可以改用 JWTs,这将使您能够将到期日期放入可以验证的令牌中。 JWT 的 HS256 算法也使用了 HMAC,也解决了这个问题。

使用键控哈希应该是高效的,并且没有数据库查找的存储、维护和开销。

你说的 UID 是指 UUID 吗?

Remember that:

the purpose of a [UUID] is to be globally unique, not to be unguessable.

[UUIDs] are designed for uniqueness, not for security.

你最好使用安全的熵源(比如另一个 CSPRNG)即时生成 128 位令牌。您可能希望在服务器端使用 SHA-256 对这些(不加盐)进行哈希处理,以防止任何数据泄漏漏洞,这意味着攻击者可以验证任何电子邮件地址。