在开始将其标记为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的状态?
已添加:为了澄清,我想知道我可以相信它是多么随机,因此 - 我在哪里可以使用它。所以,让我们在这里建立一个粗略的“随机性”量表:
我在想到是否可以将它们用作数据库ID时,是否可以将Guid.comb算法实现与System.Guid.NewGuid()
一起使用(如NHibernate所做的那样)是否存在缺陷
答案 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 comment和this one,GUID生成 是根据加密安全RNG(CryptGenRandom
)实现的。但这似乎是一个未记录的实施细节。 (我还没有对此进行验证 - 这是在互联网上的随机评论,需要一卡车的盐量。)
(*“不太可能”的意思是“在宇宙结束之前任何人找到重复的GUID的可能性低于您个人赢得彩票的机会。”实施错误除外当然。)
答案 6 :(得分:0)
它们是随机的,因此在数学上可以证明碰撞不应该发生很长时间,因此您可以假设它们在全球范围内是唯一的。但是,它们不加密强,因为这需要真正的随机性,这在没有专用硬件的计算机中实际上是不可能的。
答案 7 :(得分:0)
关注使用GUID作为行标识符的问题:
GUID适用于面向复制的数据库,或者在将数据添加到数据库之前提前生成行。如果您不需要GUID来解决特定问题,请尝试坚持增量编号。 GUID使调试和测试变得复杂一点。
你提到的文章中的COMB方法实际上看起来非常棒。我没有意识到,谢谢你! ( p.s。该文章的打印机友好版本读得更好)
因此,如果您不需要提前生成GUID,则可以让数据库为您处理GUID生成。如果您开始一次性添加10,000个记录,那么您只会注意到速度差异,这是您不应该做的,这就是批量导入的目的。
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可以提供更少的冲突机会。