随机是如何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立一个粗略的“随机性”
- 基本随机性,以当前时间为种子。 可用于在纸牌洗牌,但没有其他碰撞,即使没有尝试也很容易。
- 更高级的随机性,不仅使用时间,而且还使用其他机器特定的种子因素。 也许在系统启动时也只播种一次。 这可以用于在数据库中生成ID,因为重复是不太可能的。 尽pipe如此,这对安全性并不好,因为可以用足够的努力预测结果。
- 使用设备噪声或其他先进的随机性来源进行密码随机分配。 每次调用都要重新播种,或者至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的碰撞机会。