Java的UUID.randomUUID()方法生成的UUID重复出现了。

6
我们注意到一组将近200,000个UUID,相隔两个月重复出现,我想知道是否有人看到过类似的情况。
UUID是使用UUID.randomUUID()生成的。在深入研究此问题时(查看Java源代码),randomUUID()在底层使用SecureRandom(),而SecureRandom()又使用NativePRNG。据我了解,NativePRNG使用/dev/urandom获取其种子。当然,这意味着令人困惑-即/dev/urandom在两个月后以某种方式向NativePRNG返回了相同的种子。据我所知,一旦实例化PRNG,它就不会重新播种。这是一个长时间运行的作业,它正在侦听消息并使用UUID作为其ID。伪代码如下: <接收消息> String uuid = UUID.randomUUID().toString(); String fname = h.composeArtifact(uuid);
操作系统是Centos 6,在运行JDK1.6的AWS EC2实例上运行。是否有人在过去看到/经历过这种情况?看起来像是“永远不会发生”的事情...

我不确定这是一个安全问题,而是一个Java内部问题。 - schroeder
这两种情况下它们都是从新创建的实例生成的吗? - SilverlightFox
1
如果用于保留UUID种子的任何内部存储是通过Chef/Puppet/虚拟机快照之一来进行管理的文件,那该怎么办呢?我认为询问如何存储和操作这个所谓唯一种子以及操作系统管理方式是否可能导致其被重置到过去值是合理的。同样有趣的是Java中使用的PRNG是否有可能循环使用小子集的值,以及攻击者如何检测到这种情况以及多久发生一次。 - Steve Dodier-Lazaro
1
你说“一组20万个UUID”——是从多少个中选出来的? - fge
1
我看到的情况与你一模一样。我刚刚使用testng运行了一个测试@Test(threadPoolSize = 50, invocationCount = 2)。当我将invocationCount = 1时,我的测试正常运行。但是当我将其设置为2或更多以进行并行线程测试时,测试失败了。我一直在研究并意识到我使用UUID.randomUUID()生成的测试对象ID在所有线程中都是完全相同的。我通过为每个线程添加随机延迟来解决了这个问题。换句话说:如果线程恰好同时运行,则在所有线程中生成的UUID相同。 - Oliver Hausler
1个回答

19
从JDK 1.6源代码中可以看出,UUID.randomUUID()实际上依赖于一个java.util.SecureRandom实例。如果你得到了一系列重复的UUID,则要么你非常幸运(或非常不幸,这取决于你的观点),要么有人玩弄了VM快照,或者你的Java配置存在问题。
当进行VM快照时,记录了机器、进程和RAM的完整状态。如果存在已经实例化的SecureRandom实例的活动进程,则恢复快照将还原该状态,因此每次恢复发生时,SecureRandom输出的随机值序列将是相同的,直到SecureRandom/dev/urandom重新生成种子(/dev/urandom不断收集“随机”的物理事件,但这些事件不会影响SecureRandom状态,直到下一次重新生成种子)。

Java配置可能会影响SecureRandom,因为SecureRandom不是PRNG,而是一个围绕着由合法注册的加密提供者提供的SecureRandomSpi实例的外壳。Sun的JDK带有一个默认实现,通常利用系统资源(在Linux上为/dev/urandom)。但是,这可以进行配置;查找java.security.egd系统属性以及java.security文件中的securerandom.source属性。默认提供程序也可以完全替换为执行不同操作(可能非常糟糕)的备选实现。有关详细信息,请参见this answer。验证确实使用了什么随机源可能有些复杂,但您可以尝试使用strace启动进程,它将显示系统调用,因此是否在某个时间点打开了/dev/random/dev/urandom

如果您的Java配置正常,并且没有使用VM快照的游戏,并且您确信您确实获得了与以前相同的UUID序列,那么您真的应该买一张Powerball彩票(但我不真诚地相信这种情况)。

我很震惊地发现,显然在没有任何意图的情况下,我完全反对了这个答案,并且由于时间太久已经无法撤销。我一定是在阅读时无意中点击了它。虽然这不会对你的203k声誉评分造成负面影响,但很抱歉,这并非我的本意。 - Craig Tullis
@CraigTullis:你可以随时进行一次小编辑来解除限制,然后取消踩。这不应该成为习惯,但这是一种在更改后撤销错误/更正某些内容的方法之一。我刚添加了一个缺失的单词,所以如果你愿意,现在可能可以取消你的踩。 :) - buddemat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接