使用UUID唯一标识某事物有多安全(我正在将它用于上传到服务器的文件)?据我了解,它是基于随机数的。但是,在我看来,只要有足够的时间,它最终将以完全偶然的机会自我重复。是否有更好的系统或某种类型的模式可以缓解此问题?

评论

对于“足够的时间”足够大的值:)

“ UUID有多独特?”我相信,这是世界上独一无二的。 ;)

除非您打算在Venus上进行开发,否则GUID应该足够。

“独特”意味着永不碰撞。如果它有可能发生碰撞,那么它并不是唯一的。因此,根据定义,UUID不是唯一的,并且只有在您准备好可能发生的碰撞而不考虑碰撞机会的情况下,UUID才是安全的。否则,您的程序就是不正确的。您可以说UUID为“几乎唯一”,但这并不意味着它是“唯一的”。

UUID是唯一的“出于实用目的”-生成重复值的可能性极小,这一事实并不会使程序依赖于此错误,除非在极少数情况下,生成的ID开始使可能性具有统计意义。

#1 楼

非常安全:


某人被陨石击中的年风险
估计为170亿,这是一个机会,这意味着大约0.00000000006(6×10-11),相当于每年创建数十万亿个UUID并重复一个
的几率。换句话说,只有在接下来的100年中每秒生成10亿个UUID之后,仅创建一个副本的可能性才约为50%。


>注意:


但是,这些概率仅在使用足够的熵生成UUID时成立。否则,重复的概率可能会更高,因为统计差异可能会更低。对于分布式
应用程序需要唯一的标识符,以便即使合并来自许多
设备的数据时UUID也不冲突,每个设备上使用的种子和生成器的随机性必须可靠在应用程序的生命周期中。如果这不可行,则RFC4122建议使用名称空间变体



来源:Wikipedia文章“通用唯一”的“随机UUID重复概率”部分标识符(链接会导致从2016年12月开始进行修订,然后对该部分进行修改,然后进行修改)。

另请参阅同一主题的通用主题“碰撞”中有关同一主题的当前部分。

评论


我喜欢维基百科的这一部分:但是,仅当使用足够的熵生成UUID时,这些概率才成立。否则,重复的可能性可能会更高,因为统计差异可能会更低。那么重复注意到这句话的真正机会是什么?我们不能在计算机上创建真实的随机数,可以吗?

–芒
2014年8月29日上午10:46

实际上,已经进行了很多工作,找到了将尽可能多的熵(“真正的随机性”,我想您会称呼它)引入随机数API的方法。请参阅en.wikipedia.org/wiki/Entropy_%28computing%29

– Broofa
2014年12月6日13:48

实际上,发生碰撞的可能性比我想象的要高。我猜是生日悖论。

–卡梅伦
17年1月10日在17:51

您可以确认在应用程序执行之间使用UUID是安全的吗? (例如python脚本)

–乔治Sp
18年9月8日在18:12

如何使用“足够熵”在Node.js中生成UUID?

–linus_hologram
2月24日20:17

#2 楼

如果“给定的时间”是指100年,并且以每秒10亿的速度创建它们,那么是的,在100年后发生碰撞的可能性为50%。

评论


但是只有在为这些ID用完256艾字节的存储空间之后。

–鲍勃·阿曼(Bob Aman)
09年9月10日在7:04

有趣的是,您可以连续生成两个相同的东西,当然这是在巧合的巧合,运气和神圣干预的情况下产生的,尽管赔率令人难以置信,但仍有可能! :D是的,不会发生。只是出于娱乐考虑创建副本的那一刻而已!截图视频!

–scalabl3
2015年10月20日19:11



唯一性纯粹是因为随机性吗?还是还有其他因素? (例如时间戳记,ip等)

–曾伟诗
16年5月5日在15:54

@TheTahaan那不是随机的意思。这并不意味着“完全不可预测”-通常它们遵循某种分布。如果掷出10个硬币,则获得2个正面,3个反面和5个正面的机会非常低(2 ^ -10,约0.001)。这确实是随机的,但我们绝对可以知道获得特定结果的机会。我们只是无法提前说是否会发生。

–Richard Rast
16 Dec 7'在15:07

只是为了解释该实现方式的错误之处,他们使用的是版本1 UUID,它依赖于时间戳和mac地址的组合来实现其唯一性。但是,如果您生成UUID的速度足够快,则时间戳尚未增加。在这种情况下,您的UUID生成算法应该跟踪上次使用的时间戳并将其递增1。显然,他们没有采取该步骤。但是,由同一台计算机在短时间内正确生成的所有版本1 UUID都将表现出明显的相似性,但仍应是唯一的。

–鲍勃·阿曼(Bob Aman)
17年8月8日在22:32

#3 楼

UUID的类型不只一种,因此“安全性”取决于您使用的类型(UUID规范称为“版本”)。


版本1是基于时间的加上MAC地址UUID。 128位包含用于网卡MAC地址的48位(由制造商唯一分配)和60位时钟,分辨率为100纳秒。该时钟包裹在公元3603年,因此至少在此之前这些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年以后)。

那么,为什么每个人都不能只使用版本1 UUID?这是因为版本1 UUID揭示了生成它的机器的MAC地址,并且它们是可以预测的-两件事可能会对使用这些UUID的应用程序产生安全影响。

评论


当它们由同一台服务器为许多人生成时,默认为版本1 UUID具有严重的问题。我默认使用版本4 UUID,因为您可以快速编写一些东西以任何语言或平台(包括javascript)生成一个。

–贾斯汀·波佐尼尔(Justin Bozonier)
13年4月24日在14:58

@Hoylen好解释!但这需要夸大吗?

–迪努普·帕洛利
2014-09-16 11:32

从理论上讲,它是由制造商唯一分配的。

–橙色狗
2015年11月6日,11:04

一个人不必在一秒钟内生成1000万个版本1 UUID即可遇到重复;一个人只需在单个“刻度”的范围内生成一批16,384个UUID,即可使序列号溢出。我已经看到这种情况的发生是由于幼稚地依赖于时钟源,该时钟源(1)具有μs级粒度,并且(2)不能保证是单调的(不是系统时钟)。请注意使用的UUID生成代码,尤其要注意基于时间的UUID生成器。它们很难正确安装,因此在使用它们之前要对其进行负载测试。

–迈克·斯特罗贝尔(Mike Strobel)
17 Mar 20 '17在18:08



生成的v4 UUID之间的时间跨度是否可能导致更多的碰撞概率?我的意思是,在交通繁忙的应用中,假设同时生成数千个uuid,与在相对较长的时间内生成相同数量的uuid相比,发生碰撞的机会是否更多?

–乔纳森
19/09/10'20:27在

#4 楼

答案可能很大程度上取决于UUID版本。
许多UUID生成器使用版本4随机数。但是,其中许多使用Pseudo随机数生成器来生成它们。
如果使用种子播种不佳,周期短的PRNG来生成UUID,我会说这不是很安全。一些随机数生成器的方差也很差。即比其他号码更偏爱某些号码。
因此,它仅与生成它的算法一样安全。
另一方面,如果您知道这些问题的答案,那么我认为是版本4 uuid应该非常安全使用。实际上,我正在使用它来识别网络块文件系统上的块,并且到目前为止还没有冲突。
就我而言,我正在使用的PRNG是一台MERsenne Twister,我在使用时要小心它的播种方式来自多个来源,包括/ dev / urandom。 Mersenne twister的周期为2 ^ 19937 −1。要花很长时间才能看到重复的uuid。
因此,请选择一个好的库或自己生成它,并确保使用体面的PRNG算法。

#5 楼

从Wikipedia引用:


因此,任何人都可以创建UUID并使用
来识别
某些东西,并且可以确信
标识符永远不会
任何人无意中将其用于
其他任何事情


继续详细解释了其实际安全性。因此,请回答您的问题:是的,它足够安全。

#6 楼

我同意其他答案。 UUID对于几乎所有实际目的1都是安全的,当然对您而言也是如此。

但是(假设)不是。


是否有更好的系统或某种类型的模式可以缓解此问题?


有以下两种方法:


使用更大的UUID。例如,假设您有可靠的entropy2,则使用256或512或...,而不是128个随机位,而将每个添加到4型样式UUID的位都减少一半的碰撞概率。
构建一个集中式或分布式服务,该服务生成UUID并记录其曾经发布的每一个。每次生成新的UUID时,都会检查该UUID之前从未发行过。如果我们假设运行该服务的人员绝对值得信赖,廉洁等,那么从技术上讲,实现该服务将是直截了当的。不幸的是,它们并非……尤其是在政府的安全组织有可能干涉的情况下。因此,这种方法可能不切实际,并且在现实世界中可能是不可能的。


1-如果UUID的唯一性决定了核导弹是否在贵国首都发射,那么很多您的同胞不会被“可能性极低”说服。因此是我的“几乎所有”资格。

2-这是您要解决的一个哲学问题。有没有真正随机的东西?我们怎么知道不是吗?我们所知道的宇宙是模拟吗?

3-如果有人知道关于这个问题的任何研究论文,请发表评论。

评论


我只想指出,方法2基本上击败了使用UUID的主要目的,并且您也可以在此时使用经典的编号ID。

–Petr Vnenk
5月19日10:33

我不同意。顺序编号的ID的缺陷在于它们太容易猜测。您应该能够以一种难以猜测的UUID的方式来实现方法2。

– Stephen C
5月19日10:42



但是,即使您所说的话,您基本上可以使用任何其他随机字符串/数字并仅检查重复项,您也没有任何理由使用UUID而不是说6个字符长的随机字符串。

–Petr Vnenk
7月3日13:01

好吧,是的,不是。这取决于ID必须是唯一的上下文。如果只要求它们在封闭系统中唯一,那么使用短随机字符串并将它们全部存储在数据库(或其他内容)中以检查重复项是可行的。但这并不能保证您具有普遍的唯一性。而且,如果在系统的整个生命周期中生成的唯一ID的数量足够大,那么您会遇到扩展问题,假设唯一ID在一段时间内是唯一的……而不仅仅是在某个时间点。

– Stephen C
7月3日14:47



#7 楼

UUID方案通常不仅使用伪随机元素,而且还使用当前系统时间,并且使用某种经常唯一的硬件ID(如果有),例如网络MAC地址。

使用UUID是因为您相信UUID可以比提供您自己的能力更好地提供唯一ID。这与使用第三方加密库而不是自己动手使用相同的理由。自己动手可能会更有趣,但是这样做通常没有责任。

#8 楼

已经做了多年了。永远不会遇到问题。

我通常将数据库设置为具有一个包含所有键和修改日期等的表。从来没有遇到过重复键的问题。

它唯一的缺点是,当您编写一些查询以快速找到一些信息时,您正在进行很多键的复制和粘贴。 。您再也没有容易记住的简短ID。

#9 楼

这是一个测试代码段,供您测试它的独特性。
受到@ 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/> 




评论


尝试使用RFC 4122版本1(日期时间和MAC地址)UUID。

– zaph
16年8月19日在14:12



#10 楼

对于UUID4,我假设其边长为360,000 km的立方体形盒子中的ID数量与沙粒数量一样多。那是一个盒子,其侧面比木星的直径长约2 1/2倍。

工作,以便有人告诉我是否弄乱了单位:


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


评论


实际上,我猜这是假设包装为100%,所以也许我应该为此添加一个因素!

–丢失
1月9日12:58

#11 楼

我不知道这对您来说是否重要,但请记住,GUID在全局上是唯一的,但GUID的子字符串不是。

评论


请记住,此处链接的参考涉及版本1 UUID(将有关生成计算机的信息等纳入ID)。其他大多数答案都谈论第4版(完全是随机的)。上面链接的Wikipedia文章en.wikipedia.org/wiki/Universally_unique_identifier解释了不同类型的UUID。

–kratenko
14年4月4日在15:18