System.Guid.NewGuid()是如何随机的? (拿两个)

问题描述 投票:41回答:9

在你开始将其标记为a duplicate之前,请读完我的意思。另一个问题是(很可能)不正确的接受答案。

我不知道.NET如何生成它的GUID,可能只有微软这样做,但它很有可能只是调用CoCreateGuid()。然而,该函数被记录为调用UuidCreate()。创建UUID的算法是pretty well documented

长话短说,尽管如此,似乎System.Guid.NewGuid()确实使用version 4 UUID generation algorithm,因为它生成的所有GUID都符合标准(参见自己,我尝试了几百万个GUID,它们都匹配)。

换句话说,除了一些已知位之外,这些GUID几乎是随机的。

这再次提出了一个问题 - 随机是如何随机的?正如每个优秀的小程序员都知道的那样,伪随机数算法只与其种子(即熵)一样随机。那么UuidCreate()的种子是什么? PRNG如何重新播种?它是加密强大的,或者如果两台计算机意外同时调用System.Guid.NewGuid(),我可以期望相同的GUID开始倾泻吗?如果收集到足够多的顺序生成的GUID,是否可以猜测PRNG的状态?

补充:为了澄清,我想知道我可以信任的随机性因此 - 我在哪里可以使用它。那么,让我们在这里建立一个粗略的“随机性”量表:

  1. 基本随机性,以当前时间为种子。可以在纸牌中使用洗牌,但是即使没有尝试也很容易碰到碰撞。
  2. 更高级的随机性,不仅使用时间,还使用其他机器特定的种子因子。也许在系统启动时也只播种一次。这可用于在DB中生成ID,因为不太可能重复。但是,它对安全性不利,因为可以用足够的努力预测结果。
  3. 密码随机,使用设备噪声或其他先进的种子随机源。每次调用或至少经常重新播种。可用于会话ID,分发给不受信任的各方等。

我在想到是否可以将它们用作DB ID,以及Guid.comb算法实现与System.Guid.NewGuid()(如NHibernate这样做)是否有缺陷时,我就得出了这个问题。

.net random guid
9个回答
34
投票

答案是:你不应该知道这一点。正如接受related question的答案所述:

GUID不保证随机性,它保证了唯一性。

关于安全性和随机性的更强有力的声明是在RFC4122中做出的,它描述了UUID格式:

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

其他任何东西都是一个实现细节(可能会受到更改)。

Windows细节

通常,人们声称Windows上的行为已被记录,因此保证GUID在加密方面是安全的。

现已归档的[MS-SECO] Windows Security Overview文件在附录A中提到:

虽然只有少数版本4 GUID需要加密随机性,但Windows中构建的所有版本4 GUID的随机位都是通过Windows CryptGenRandom加密API或等效的,用于生成加密密钥的相同源获得的。

此外,同一文件的第2.5.5节明确提到使用“秘密GUID”值作为nonce或authenticator。

但是:这件产品行为文档不是一般的规范,您通常可以基于产品的安全性(特别是在.NET的上下文中)。

实际上,上述文档描述了特定产品的实现细节。即使当前的Windows和.NET Framework 4.x实现在Windows上生成真正随机的版本4 UUID值,也无法保证System.Guid.NewGuid将来或其他.NET平台(例如Mono,Silverlight,CF ,. NET Core等)。

举个例子,早期版本的.NET Core depends on the platform中使用的UUID算法可能会得到版本1 UUID(在BSD上)。


18
投票

有些人已经暗示了这一点,但我想重复一遍,因为那里似乎存在一种误解:

随机性和唯一性是正交概念。

随机数据可以是唯一的或冗余的,同样唯一的数据可以使用随机源或确定性源(想想一个全局计数器,它为每个创建的GUID锁定和递增)。

GUID被设计为独特的,而不是随机的。如果.NET生成器似乎使用随机输入,那很好。但是,不要依赖它作为随机性的来源,既不用于加密也不用于任何其他目的(特别是,你期望得到什么分布函数?)。另一方面,您可以合理地确定.NET创建的GUID(即使是大批量)也是唯一的。


7
投票

生成随机字节但未明确记录以生成加密强随机字节的API不能被信任以产生加密强随机字节。

如果您需要加密强大的随机字节,那么您应该使用明确记录的API来生成它们。

public Guid CreateCryptographicallyStrongGuid() {
    var rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
    var data = new byte[16];
    rng.GetBytes(data);
    return new Guid(data);
}

这些GUID只是128位加密随机性。它们没有结构化,也不会发生碰撞。

有些数学,请参阅this article。使用“一般生日公式”,重新排列给出

n = sqrt(-2T * ln(p))

其中n是所选元素的数量,T是元素的总数(2 ^ 128),p是所有n个所选元素将不同的目标概率。当p = .99时,这给出* n = 2.61532104 * 10 ^ 18 *。这意味着我们可以在系统内每秒生成十亿个真正随机的GUID,持续十亿秒(32年),并且最终有99%的机会在系统中每个都是唯一的。


6
投票

随机的定义绝不与全球唯一的定义有关。

两次掷硬币并获得HH,HT,TH,TT都是随机的。 HH和HT一样随机。

两次翻转“特殊”硬币并保证只获得HT或TH是唯一性。


2
投票

根据https://msdn.microsoft.com/en-us/library/bb417a2c-7a58-404f-84dd-6b494ecf0d13#id11,自1999年Windows 2000以来,

“Windows中构建的所有版本4 GUID的随机位是通过Windows CryptGenRandom加密API或等效的,用于生成加密密钥的相同源获得的”

所以我认为它们在加密方面是安全的 - 至少在它们提供的122位熵的范围内。

另请参阅https://stackoverflow.com/a/35384818/284704,其中Will Dean通过调试步骤验证了CLR正在调用适当的安全OS随机生成器。


1
投票

GUID被设计为在您的规模上排在第2位,即“可以用于在数据库中生成ID,因为重复项不太可能*。”

至于安全性,问题不在于“它对安全性不利,因为可以用足够的努力预测结果。”问题是没有人给你一个文件化的安全保证。

实际上,根据this commentthis one,GUID生成是根据加密安全的RNG(CryptGenRandom)实现的。但这似乎是一个未记录的实施细节。 (我还没有对此进行验证 - 这是互联网上的随机评论,需要一卡车的盐量)。

(*“不太可能”意味着“在宇宙结束之前,任何人发现重复GUID的可能性都小于您个人赢得彩票的机会。”当然,实施漏洞除外。)


0
投票

它们是随机的,因此在数学上可证明碰撞不应该发生很长时间,因此您可以假设它们在全球范围内是唯一的。但是,它们在加密方面并不强大,因为这需要真正的随机性,这在没有专用硬件的计算机中实际上是不可能的。


0
投票

着重讨论使用GUID作为行标识符的问题:

GUID适用于面向复制的数据库,或者在将数据添加到数据库之前提前生成行。如果您不需要GUID来解决特定问题,请尝试坚持增量编号。 GUID使调试和测试变得复杂一点。

实际上,你提到的文章中的COMB方法看起来非常棒。我没有意识到,谢谢你! (p.s.该文章的打印机友好版本读得更好)

因此,如果您不需要提前生成GUID,则可以让数据库为您处理GUID生成。如果您开始一次性添加10,000个记录,那么您只会注意到的速度差异,这是您不应该做的,这就是批量导入的目的。

还可以看看Jeff on ID's vs GUID's

create table #temp ([id] uniqueidentifier primary key default(newid()), [name] varchar(20))
insert into #temp (name) values ('apple')
insert into #temp (name) values ('orange')
insert into #temp (name) values ('banana')
select * from #temp
drop table #temp

id                                   name
------------------------------------ --------------------
911B0CBD-4EED-4EB0-8488-1B2CDD915C02 banana
56CF3A80-A2DE-4949-9C9B-5F890824EA9C orange
5990B9FD-143D-41B0-89D1-957B2C57AB94 apple

-1
投票

我在某地读到,赢得彩票的机会相当于2个4字节的“GUID”冲突。标准的16字节GUID可以提供更少的冲突机会。

© www.soinside.com 2019 - 2024. All rights reserved.