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

时间:2010-04-12 11:14:46

标签: .net random guid

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

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

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

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

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

已添加:为了澄清,我想知道我可以相信它是多么随机,因此 - 我在哪里可以使用它。所以,让我们在这里建立一个粗略的“随机性”量表:

  1. 基本随机性,以当前时间为种子。可以在纸牌中使用洗牌,但即使没有尝试也很容易发生碰撞。
  2. 更高级的随机性,不仅使用时间,还使用其他机器特定的种子因子。也许在系统启动时也只播种一次。这可用于在DB中生成ID,因为不太可能重复。尽管如此,它对安全性并不好,因为可以通过足够的努力来预测结果。
  3. 使用设备噪音或其他先进的种子随机源来加密随机。每次调用或至少经常重新播种。可用于会话ID,分发给不受信任的各方等。
  4. 我在想到是否可以将它们用作数据库ID时,是否可以将Guid.comb算法实现与System.Guid.NewGuid()一起使用(如NHibernate所做的那样)是否存在缺陷

9 个答案:

答案 0 :(得分: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上)。

答案 1 :(得分:18)

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

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

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

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

答案 2 :(得分: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%的机会在系统中每个都是唯一的。

答案 3 :(得分:6)

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

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

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

答案 4 :(得分: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正在调用正确的安全操作系统随机生成器。

答案 5 :(得分:1)

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

至于安全性,问题并非“它对安全性不利,因为可以用足够的努力预测结果。”问题是没有人给你一个记录在案的安全保障。

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

(*“不太可能”的意思是“在宇宙结束之前任何人找到重复的GUID的可能性低于您个人赢得彩票的机会。”实施错误除外当然。)

答案 6 :(得分:0)

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

答案 7 :(得分: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

答案 8 :(得分:-1)

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