使用UUID唯一标识某些内容(我正在使用它来标识上传到服务器的文件)有多安全?据我所知,它是基于随机数。然而,在我看来,只要有足够的时间,它最终会完全偶然地重复它自己。是否有更好的系统或某种类型的模式来缓解这个问题?


当前回答

这里有一个测试片段供您测试它的独特性。 灵感来自@scalabl3的评论

有趣的是,你可以连续生成2个完全相同的结果,当然是在令人难以置信的巧合、运气和神的干预下,尽管有不可思议的几率,但这仍然是可能的!:是的,不会发生的。我这么说只是为了好玩,想想你创造了一个复制品的那一刻!视频截图!- scalab13 10月20日15日19:11

如果您觉得幸运,请选中复选框,它只检查当前生成的id。如果您希望进行历史记录检查,请不勾选。 请注意,如果您不勾选它,您可能会在某些时候耗尽ram。我试图使它对cpu友好,以便在需要时可以快速中止,只需再次点击运行代码片段按钮或离开页面。

Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); } Math.trueRandom = (function() { var crypt = window.crypto || window.msCrypto; if (crypt && crypt.getRandomValues) { // if we have a crypto library, use it var random = function(min, max) { var rval = 0; var range = max - min; if (range < 2) { return min; } var bits_needed = Math.ceil(Math.log2(range)); if (bits_needed > 53) { throw new Exception("We cannot generate numbers larger than 53 bits."); } var bytes_needed = Math.ceil(bits_needed / 8); var mask = Math.pow(2, bits_needed) - 1; // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111 // Create byte array and fill with N random numbers var byteArray = new Uint8Array(bytes_needed); crypt.getRandomValues(byteArray); var p = (bytes_needed - 1) * 8; for(var i = 0; i < bytes_needed; i++ ) { rval += byteArray[i] * Math.pow(2, p); p -= 8; } // Use & to apply the mask and reduce the number of recursive lookups rval = rval & mask; if (rval >= range) { // Integer out of acceptable range return random(min, max); } // Return an integer that falls within the range return min + rval; } return function() { var r = random(0, 1000000000) / 1000000000; return r; }; } else { // From http://baagoe.com/en/RandomMusings/javascript/ // Johannes Baagøe <baagoe@baagoe.com>, 2010 function Mash() { var n = 0xefc8249d; var mash = function(data) { data = data.toString(); for (var i = 0; i < data.length; i++) { n += data.charCodeAt(i); var h = 0.02519603282416938 * n; n = h >>> 0; h -= n; h *= n; n = h >>> 0; h -= n; n += h * 0x100000000; // 2^32 } return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 }; mash.version = 'Mash 0.9'; return mash; } // From http://baagoe.com/en/RandomMusings/javascript/ function Alea() { return (function(args) { // Johannes Baagøe <baagoe@baagoe.com>, 2010 var s0 = 0; var s1 = 0; var s2 = 0; var c = 1; if (args.length == 0) { args = [+new Date()]; } var mash = Mash(); s0 = mash(' '); s1 = mash(' '); s2 = mash(' '); for (var i = 0; i < args.length; i++) { s0 -= mash(args[i]); if (s0 < 0) { s0 += 1; } s1 -= mash(args[i]); if (s1 < 0) { s1 += 1; } s2 -= mash(args[i]); if (s2 < 0) { s2 += 1; } } mash = null; var random = function() { var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 s0 = s1; s1 = s2; return s2 = t - (c = t | 0); }; random.uint32 = function() { return random() * 0x100000000; // 2^32 }; random.fract53 = function() { return random() + (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 }; random.version = 'Alea 0.9'; random.args = args; return random; }(Array.prototype.slice.call(arguments))); }; return Alea(); } }()); Math.guid = function() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.trueRandom() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }; function logit(item1, item2) { console.log("Do "+item1+" and "+item2+" equal? "+(item1 == item2 ? "OMG! take a screenshot and you'll be epic on the world of cryptography, buy a lottery ticket now!":"No they do not. shame. no fame")+ ", runs: "+window.numberofRuns); } numberofRuns = 0; function test() { window.numberofRuns++; var x = Math.guid(); var y = Math.guid(); var test = x == y || historyTest(x,y); logit(x,y); return test; } historyArr = []; historyCount = 0; function historyTest(item1, item2) { if(window.luckyDog) { return false; } for(var i = historyCount; i > -1; i--) { logit(item1,window.historyArr[i]); if(item1 == history[i]) { return true; } logit(item2,window.historyArr[i]); if(item2 == history[i]) { return true; } } window.historyArr.push(item1); window.historyArr.push(item2); window.historyCount+=2; return false; } luckyDog = false; document.body.onload = function() { document.getElementById('runit').onclick = function() { window.luckyDog = document.getElementById('lucky').checked; var val = document.getElementById('input').value if(val.trim() == '0') { var intervaltimer = window.setInterval(function() { var test = window.test(); if(test) { window.clearInterval(intervaltimer); } },0); } else { var num = parseInt(val); if(num > 0) { var intervaltimer = window.setInterval(function() { var test = window.test(); num--; if(num < 0 || test) { window.clearInterval(intervaltimer); } },0); } } }; }; Please input how often the calulation should run. set to 0 for forever. Check the checkbox if you feel lucky.<BR/> <input type="text" value="0" id="input"><input type="checkbox" id="lucky"><button id="runit">Run</button><BR/>

其他回答

很安全:

一个人被陨石击中的年风险是 估计是170亿分之一的几率,也就是说 概率约为0.00000000006 (6 × 10−11),相当于几率 在一年内创造出几十万亿uuid,并拥有一个uuid 复制。换句话说,只有在每次生成10亿个uuid之后 第二,在接下来的100年里,只创造一个的概率 重复率约为50%。

警告:

However, these probabilities only hold when the UUIDs are generated using sufficient entropy. Otherwise, the probability of duplicates could be significantly higher, since the statistical dispersion might be lower. Where unique identifiers are required for distributed applications, so that UUIDs do not clash even when data from many devices is merged, the randomness of the seeds and generators used on every device must be reliable for the life of the application. Where this is not feasible, RFC4122 recommends using a namespace variant instead.

来源:维基百科关于通用唯一标识符的文章的随机UUID重复概率部分(链接指向2016年12月的修订版,在编辑重新编辑该部分之前)。

另请参阅同一篇通用唯一标识符文章中关于同一主题的当前部分,碰撞。

我不知道这对您是否重要,但请记住,guid是全局惟一的,但guid的子字符串不是。

我应该提一下,我在亚马逊上买了两个外接希捷驱动器,它们有相同的设备UUID,但PARTUUID不同。大概他们用来格式化硬盘的克隆软件也复制了UUID。

显然,UUID冲突更可能是由于有缺陷的克隆或复制过程而不是由于随机巧合而发生。在计算UUID风险时请记住这一点。

对于UUID4,我认为在一个边长360000公里的立方体盒子中,id的数量大约与沙粒的数量相同。这是一个边长约为木星直径2.5倍的盒子。

如果我搞砸了单位,就会有人告诉我:

沙粒体积0.00947mm^3 (Guardian) UUID4有122个随机位-> 5.3e36可能的值(维基百科) 那么多沙粒的体积= 5.0191e34 mm^3或5.0191e+25m^3 体积= 3.69E8m或369,000km的立方箱的边长 木星直径:139,820公里(谷歌)

摘自维基百科:

因此,任何人都可以创建UUID并使用 用它来表示某物 合理相信 标识符永远不会是 无意中被某人用于 其他东西

它还非常详细地解释了它的安全性。所以回答你的问题:是的,它足够安全。