使用UUID唯一标识某事物有多安全(我正在将它用于上传到服务器的文件)?据我了解,它是基于随机数的。但是,在我看来,如果有足够的时间,它最终会以纯偶然的机会自我重复。是否有更好的系统或某种模式来缓解此问题?
使用UUID唯一标识某事物有多安全(我正在将它用于上传到服务器的文件)?据我了解,它是基于随机数的。但是,在我看来,如果有足够的时间,它最终会以纯偶然的机会自我重复。是否有更好的系统或某种模式来缓解此问题?
Answers:
非常安全:
估计某人被陨石击中的年度风险是170亿的一次机会,这意味着该概率约为0.00000000006(6×10 -11),这相当于制造数十万亿个UUID的几率一年内重复一次。换句话说,只有在接下来的100年中每秒生成10亿个UUID之后,才创建一个副本的可能性约为50%。
警告:
但是,仅当使用足够的熵生成UUID时,这些概率才成立。否则,重复的可能性可能会更高,因为统计差异可能会更低。在分布式应用程序需要唯一标识符的情况下,即使合并了许多设备的数据,UUID也不冲突,每个设备上使用的种子和生成器的随机性在应用程序的生命周期内必须可靠。如果这不可行,则RFC4122建议改用命名空间变体。
资料来源:Wikipedia文章“通用唯一标识符”的“ 随机UUID重复概率”部分(链接导致自2016年12月起进行修订,然后对该部分进行了修改)。
另请参阅同一通用唯一标识符文章Collisions中有关同一主题的当前部分。
如果“给定的时间”是指100年,并且以每秒10亿的速度创建它们,那么是的,在100年后发生碰撞的机率是50%。
UUID的类型不止一种,因此“安全性”取决于您所使用的类型(UUID规范称为“版本”)。
版本1是基于时间的,加上MAC地址UUID。128位包含网卡的MAC地址的48位(由制造商唯一分配)和60位时钟,分辨率为100纳秒。该时钟包裹在3603 AD中,因此至少在此之前这些UUID是安全的(除非您每秒需要超过一千万个新的UUID或有人克隆您的网卡)。我说“至少”是因为时钟始于1582年10月15日,所以在绕完时钟大约400年之后,甚至有很小的重复机会。
版本4是随机数UUID。有六个固定位,UUID的其余部分为122位随机性。请参阅Wikipedia或其他分析,描述重复的可能性很小。
版本3使用MD5,版本5使用SHA-1创建那些122位,而不是随机或伪随机数生成器。因此,就安全性而言,就像版本4是一个统计问题一样(只要您确保摘要算法正在处理的内容始终是唯一的)。
版本2与版本1类似,但时钟更小,因此可以更快地环绕。但是由于版本2的UUID是DCE的,所以您不应该使用它们。
因此,对于所有实际问题,它们都是安全的。如果您对将其留给概率不满意(例如,您是那种担心地球在您的一生中被大型小行星摧毁的人),只需确保您使用的是版本1 UUID,并保证它是唯一的( ,除非您打算活到3603 AD以上)。
那么,为什么每个人都不只是使用版本1 UUID?这是因为版本1 UUID揭示了生成它的机器的MAC地址,并且它们是可以预测的-两件事可能会对使用这些UUID的应用程序带来安全隐患。
答案可能很大程度上取决于UUID版本。
许多UUID生成器使用版本4随机数。但是,其中许多使用伪随机数生成器来生成它们。
如果使用种子期较短的PRNG来生成UUID,我会说它根本不是很安全。
因此,它仅与生成它的算法一样安全。
另一方面,如果您知道这些问题的答案,那么我认为第4版uuid应该非常安全。实际上,我正在使用它来识别网络块文件系统上的块,并且到目前为止还没有发生冲突。
就我而言,我使用的PRNG是一台mersenne扭曲器,并且我对它的播种方式非常谨慎,该播种来自多个来源,包括/ dev / urandom。梅森捻线器的周期为2 ^ 19937 −1。这将是非常长的时间,我才能看到重复的uuid。
我同意其他答案。UUID对于几乎所有实际用途1都是安全的,当然对您而言也是如此。
但假设(假设)事实并非如此。
是否有更好的系统或某种模式来缓解此问题?
以下是几种方法:
使用更大的UUID。例如,假设您有可靠的熵源2,则可以使用256或512或...来代替128个随机位,而将每个位添加到4型样式UUID会将碰撞的可能性降低一半。。
构建一个集中式或分布式服务,该服务生成UUID并记录它曾经发布的每一个。每次生成新的UUID时,都会检查该UUID从未发行过。如果我们假设运行该服务的人员绝对值得信赖,廉洁等,那么从技术上讲,要实现这种服务将是直截了当的。不幸的是,它们并非……尤其是在政府的安全组织有可能干涉的情况下。因此,这种方法可能不切实际,在现实世界中可能是3种不可能的方法。
1-如果UUID的唯一性决定了核导弹是否是在贵国首都发射的,那么许多同胞将不会被“可能性极低”说服。因此,我的“几乎所有”资格。
2-这是您要解决的一个哲学问题。有没有真正随机的东西?我们怎么知道不是吗?我们所知道的宇宙是模拟吗?有没有一位上帝可以想象“调整”物理定律以改变结果?
3-如果有人知道有关此问题的任何研究论文,请发表评论。
这是一个测试代码段,供您测试其独特性。受@ scalabl3的评论启发
有趣的是,您可以连续生成两个相同的东西,当然这在巧合的巧合,运气和神圣干预的水平上来说,尽管有不可思议的赔率,但仍然有可能!:D是的,不会发生。只是出于娱乐考虑创建副本的那一刻而已!截图视频!– scalabl3 2015年10月20日,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/>
我不知道这对您来说是否重要,但请记住,GUID在全局上是唯一的,但GUID的子字符串不是。
对于UUID4,我可以使它的ID数量与边长360,000 km的立方体形盒子中的沙粒数量一样多。那是一个盒子,其边长是木星直径的约2 1/2倍。
工作,以便有人可以告诉我是否弄乱了单位: