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

在你开始把这个标记为重复之前 ,请把我读出来。 另一个问题有(很有可能)不正确的接受答案。

我不知道.NET如何生成它的GUID,可能只有微软,但它很可能只是调用CoCreateGuid() 。 但是该函数被logging为调用UuidCreate() 。 而创build一个UUID的algorithm已经很好的logging了 。

长话短说, System.Guid.NewGuid() ,似乎System.Guid.NewGuid()确实使用版本4的UUID生成algorithm ,因为它生成的所有GUID都与条件匹配(请参阅我自己,我尝试了几百万个GUID,它们全部匹配)。

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

这再次提出了这个问题 – 随机性多么的随意? 正如每个好的小程序员所知道的,一个伪随机数algorithm只和它的种子一样随机(又称熵)。 那么UuidCreate()的种子是什么? PRNG重新播种了多less? 它是密码强大的,还是我可以期望相同的GUID开始倾吐,如果两台计算机不小心同时呼叫System.Guid.NewGuid() ? 如果收集足够多的顺序生成的GUID,PRNG的状态可以被猜测吗?

补充:为了澄清,我想了解我可以如何信任它,因此 – 我可以在哪里使用它。 所以,我们在这里build立一个粗略的“随机性”

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

我一直在想这个问题是否可以使用它们作为数据库ID,以及Guid.combalgorithm是否与System.Guid.NewGuid()一起实现(像NHibernate一样)会有缺陷。

对相关问题的接受答案是:

GUID不保证随机性,它保证了唯一性。 如果你想随机,使用随机生成一个string。

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

更新:为了使我的观点更清晰:即使当前的.NET 3.5实现产生了一个真正的随机guid(情况并非如此),但是不能保证在将来会出现这种情况,或者BCL的其他实现如Mono,Silverlight,CF等)

更新2:UUID的格式由RFC4122指定。 第6节对安全问题作出明确的陈述:

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

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

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

随机数据可以是唯一的或冗余的,同样独特的数据可以使用随机源或确定性源(想象一个全局计数器,locking并增加每个创build的GUID)。

GUID被devise为独特的,而不是随机的。 如果.NET生成器似乎使用随机input,很好。 但是,不要把它作为随机性的来源,既不是密码学的,也不是为了其他目的(特别是你期望得到什么分布函数?)。 另一方面,你可以合理地确定由.NET创build的GUID,即使是大量的,也是唯一的。

随机的定义决不涉及全球唯一的定义。

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

翻转一个“特殊”的硬币两次,保证你只会得到HT或TH是唯一的。

产生随机字节但没有明确logging以产生密码强的随机字节的API不能被信任以产生密码上强的随机字节。

如果你需要密码强的随机字节,那么你应该使用明确logging的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位的密码随机性。 他们没有结构,他们不会相互碰撞。

看到这篇文章的一些math。 使用“一般的生日配方”,重新排列给出

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

其中n是所选元素的数量, T是元素的总数(2 ^ 128),而p是所有n个选定元素将不同的目标概率。 当p = 0.99时 ,这给出* n = 2.61532104 * 10 ^ 18 *。 这意味着我们可以在一个系统内每秒产生10亿个真正的随机GUID,达到10亿秒(32年),并且每个系统在系统中都有99%以上的可能性。

它们是随机的,所以在math上certificate碰撞不应该发生很长一段时间,所以你可以假设它们是全球唯一的。 然而,它们不是密码强大的,因为这需要一个真正的随机性,这在没有专用硬件的计算机中是不可能的。

GUID被devise为在您的规模上的第二位,即“可以用于在数据库中生成ID,因为重复是不太可能的。

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

实际上,根据这个评论和这一个 ,GUID的生成通过密码安全的RNG( CryptGenRandom )来实现的。 但是这似乎是一个无证的实现细节。 (而且我还没有证实这一点 – 这是在互联网上的随机评论,拿一整jar盐)。

(*“不太可能”意味着“在宇宙结束之前find重复的GUID的机会小于你亲自获得彩票的机会”)。当然,实施错误除外。

专注于使用GUID作为行标识符的问题

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

实际上你提到的文章中的COMB方法看起来相当不错。 我从来没有意识到,谢谢那个! ( ps那篇文章的打印友好版本读起来好多了

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

也可以看看Jeff的ID和GUID的关系

 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 

我在某处读到,中奖彩票的机会相当于2个4字节的“GUID”碰撞。 标准的16字节的GUID将提供更less的碰撞机会。