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

2022-09-01 10:56:52

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

UUID.randomUUID() 文档说:

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

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


答案 1

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

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


答案 2

哈哈根据 UUID 规范

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

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

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库。