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

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

UUID.randomUUID()文档说:

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

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

不。根据UUID规范 :

不要以为UUID难以猜测; 例如,它们不应被用作安全function(仅仅拥有访问权限的标识符)。 可预测的随机数源将加剧这种情况。

此外,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的RFC ,并且从API文档链接到这些RFC ,您将看到并非UUID的所有位实际上都是随机的(“变体”和“版本”不是随机的)。 因此,如果正确实现,类型4 UUID(您打算使用的那种)应该具有122位(对于此实现是安全的)随机信息,总大小为128位。

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

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

这是我的建议:

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

这将需要一些工作,但如果你真的关心编写一个强大,安全的系统,这是必要的。

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

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

UUID也是长字符串(128位,然后通常是Base64(22个字符)或Base16编码(32个字符)) – 想想你的系统将如何用户友好。 就个人而言,我会使用CSRNG随机选择8个字母数字字符并返回。

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

– 更新 –

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

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

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

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

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

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

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