UUID.randomUUID()是否适合用作一次性密码?

时间:2012-06-14 02:57:25

标签: java random security uuid

作为previous discussed,确认电子邮件应该在确认链接中具有唯一的(实际上)不可猜测的代码 - 实质上是one-time password

The UUID.randomUUID() docs说:

  

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

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

9 个答案:

答案 0 :(得分:14)

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

所以是的,它可以和“安全”生成器中的122位随机数一样工作。 较短的值可能包含足够的随机性,对用户来说可能更容易(也许我是唯一一个仍在终端中阅读电子邮件的老式人,但是包含在行之间的确认网址很讨厌....)。

答案 1 :(得分:6)

否。根据UUID spec

  

不要以为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);
    }
}

答案 2 :(得分:4)

是的,使用java.util.UUID很好。没有什么需要说的。

这是我的建议:

  1. 向用户发送包含巨大密码的链接作为URL参数。
  2. 当用户点击链接时,请编写后端,以便确定参数是否正确以及用户是否已登录。
  3. 发布UUID后24小时无效。
  4. 这需要一些工作,但如果你真的关心编写一个健壮,安全的系统,那就很有必要。

答案 3 :(得分:1)

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

对于二进制计算机,

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

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

  1. 符号选自 52 个字符(两种情况下均为 26 * 2)+ 10 个数字 + 可能 15 其他字符,例如 (*, + -, ...),一般符号空间在 75 附近。
  2. 如果我们期望最小密码长度为 8
entropy = 8 * log275 ~= 8 * 6.x ~= 50

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

密码长度 = 50 / log216 = 50 / 4 ~= 12

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

密码长度 = 50 / log262 = 50 / 6 ~= 8

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

对于 UUID.randomUUID(),两个主要问题是

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

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

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

答案 4 :(得分:0)

如果它是由CSRNG生成的,那么它是不可预测的,因此可以使用。

但是,如果您发送未加密的确认电子邮件,那么您所遇到的麻烦就会浪费 - 如果攻击者能够预测您系统中的RNG结果,那么他们也有可能拦截电子邮件。

UUID也是长字符串(128位,然后通常是Base64(22个字符)或Base16编码(32个字符)) - 考虑一下系统的用户友好性。就个人而言,我会使用CSRNG随机选择8个字母数字字符并返回它们。

答案 5 :(得分:0)

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

- 更新 -

如果您不信任提供的加密强随机数生成器,您可以使用UUID代码添加一些更难以预测的参数并对其进行哈希处理。例如,

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

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

答案 6 :(得分:-1)

我认为这应该是合适的,因为它是随机生成的,而不是来自任何特定的输入(即你没有使用用户名或类似的东西) - 因此多次调用此代码会产生不同的结果。它声称它是一个128位密钥,所以它的长度足以让它破碎。

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

答案 7 :(得分:-1)

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

答案 8 :(得分:-2)

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