31

如前所述,确认电子邮件应确认链接中具有唯一的(实际上)不可猜测的代码——本质上是一次性密码

UUID.randomUUID() 文档说:

UUID 是使用加密强的伪随机数生成器生成的。

这是否意味着正确实现的 JVM 中的 UUID 随机生成器适合用作唯一的(实际上)不可猜测的 OTP?

4

8 回答 8

19

如果您阅读定义 UUID 的RFC,并从 API 文档链接到该 RFC,您会发现并非 UUID 的所有位实际上都是随机的(“变体”和“版本”不是随机的)。因此,如果正确实施,类型 4 UUID(您打算使用的那种)应该具有 122 位(对于此实施而言是安全的)随机信息,总大小为 128 位。

所以是的,它与来自“安全”生成器的 122 位随机数一样有效。 较短的值可能包含足够的随机性,并且对用户来说可能更容易(也许我是唯一仍然在终端中阅读电子邮件的老式人,但是跨行的确认 URL 很烦人......) .

于 2012-06-14T03:17:49.910 回答
17

,根据UUID 规范

不要假设 UUID 很难猜;例如,它们不应该用作安全功能(仅拥有授予访问权限的标识符)。一个可预测的随机数源会加剧这种情况。

此外,UUID 只有 16 个可能的字符(0 到 F)。SecureRandom您可以使用(感谢@erickson)生成更紧凑且更明确安全的随机密码。

import java.security.SecureRandom;
import java.math.BigInteger;

public final class PasswordGenerator {
    private SecureRandom random = new SecureRandom();

    public String nextPassword() {
        return new BigInteger(130, random).toString(32);
    }
}

附言

我想给出一个清楚的例子,说明使用 UUID 作为安全令牌可能会导致问题:

uuid-random中,我们 通过巧妙的方式在内部重新使用随机字节发现了巨大的速度提升,从而产生了可预测的 UUID。尽管我们没有发布更改,但 RFC 允许这样做,并且此类优化可能会潜入您的 UUID 库而不引起注意。

于 2016-10-16T03:50:39.450 回答
11

是的,使用 ajava.util.UUID很好,randomUUID方法从加密安全源生成。没有太多需要说的了。

这是我的建议:

  1. 向用户发送一个包含巨大密码的链接作为 URL 参数。
  2. 当用户单击链接时,编写您的后端,以便确定参数是否正确以及用户是否已登录。
  3. UUID 在发布 24 小时后失效。

这将需要一些工作,但如果您真的关心编写一个健壮、安全的系统,这是必要的。

于 2012-06-14T04:19:08.893 回答
1

密码强度可以根据所需的熵进行量化(越高越好)。

对于二进制计算机,

熵 = 密码长度 * log 2(符号空间)
符号空间是可供选择的唯一符号(字符)总数

对于使用 qwerty 键盘的普通英语用户,

  1. 符号是从52字符中选择的(两种情况下都是 26 * 2)+10数字 + 可能还有15其他字符,例如 (*, + -, ...),一般符号空间在75.
  2. 如果我们期望最小密码长度为8
熵 = 8 * log 2 75 ~= 8 * 6.x ~= 50

要为仅使用十六进制(符号空间 = 0-9,af)50的自动生成的一次性密码实现熵( ),16

密码长度 = 50 / log 2 16 = 50 / 4 ~= 12

如果应用程序可以放宽考虑完整的区分大小写的英文字母和数字,样本空间将是62(26 * 2 + 10),

密码长度 = 50 / log 2 62 = 50 / 6 ~= 8

这将用户输入的字符数减少到 8 个(从 12 个十六进制)。

使用 UUID.randomUUID(),两个主要问题是

  1. 用户必须输入 32 个字符(对用户不友好)
  2. 实现必须确保唯一性标准(与库版本和语言依赖关系紧密耦合)

我知道这不是一个直接的答案,考虑到安全性和可用性限制,它真的取决于应用程序所有者来选择最佳策略。

就个人而言,我不会使用 UUID.randomUUID() 作为一次性密码。

于 2021-01-29T01:45:20.273 回答
-2

确认链接的随机代码的要点是攻击者不应该能够猜测或预测该值。如您所见,要找到确认链接的正确代码,128 位长度的 UUID 会产生 2^128 个不同的可能代码,即 340,282,366,920,938,463,463,374,607,431,768,211,456 个可能的代码尝试。我想你的确认链接不是用来发射核武器的,对吧?这对于攻击者来说很难猜到。它是安全的。

- 更新 -

如果您不信任提供的加密强随机数生成器,您可以将一些更不可预测的参数与 UUID 代码一起放入并散列它们。例如,

code = SHA1(UUID、进程PID、线程ID、本地连接端口号、CPU温度)

这使得预测变得更加困难。

于 2012-06-14T03:15:19.907 回答
-3

我认为这应该是合适的,因为它是随机生成的,而不是从任何特定输入中生成的(即你没有用用户名或类似的东西来提供它)——所以多次调用这段代码会产生不同的结果。它声明它是一个 128 位密钥,因此它的长度足以破解是不切实际的。

然后您打算使用此密钥来加密一个值,还是希望将其用作实际密码?无论如何,您都需要将密钥重新解释为可以通过键盘输入的格式。例如,进行 Base64 或 Hex 转换,或以某种方式将值映射到字母数字,否则用户将尝试输入键盘上不存在的字节值。

于 2012-06-14T03:03:44.943 回答
-4

它非常适合作为一次性密码,因为即使我已经为正在工作的应用程序实现了相同的密码。此外,您共享的链接说明了一切。

于 2012-06-14T03:05:56.423 回答
-4

我认为 java.util.UUID 应该没问题。您可以从这篇文章中找到更多信息:

于 2018-05-28T01:19:01.257 回答