UUID ne kadar benzersizdir?


451

Bir şeyi benzersiz bir şekilde tanımlamak için UUID kullanmak ne kadar güvenli (sunucuya yüklenen dosyalar için kullanıyorum)? Anladığım kadarıyla, rastgele sayılara dayanıyor. Ancak bana öyle geliyor ki, yeterli zaman verildiğinde, eninde sonunda kendini saf şansla tekrarlayacaktır. Bu sorunu hafifletmek için daha iyi bir sistem veya bir model var mı?


11
"Yeterli zaman" yeterince büyük bir değer için :)

91
"UUID ne kadar eşsiz?" Evrensel olarak benzersiz, inanıyorum. ;)
Miles

29
Ve Venüs üzerinde gelişmeyi planlamıyorsanız, bir GUID yeterli olmalıdır.
skaffman

1
burada daha fazla ayrıntı ve jeneratör: çevrimiçi uuid jeneratör
Dave

2
"eşsiz" asla çarpışmayacak demektir . Çarpışma potansiyeli varsa, benzersiz değildir . Bu nedenle, tanım gereği, UUID benzersiz değildir ve yalnızca çarpışma olasılığından bağımsız olarak potansiyel çarpışmalara hazırsanız güvenlidir. Aksi takdirde, programınız yanlıştır. UUID'yi "neredeyse benzersiz" olarak söyleyebilirsiniz, ancak bu "benzersiz" anlamına gelmez.
Eonil

Yanıtlar:


446

Çok güvenli:

belirli bir kişinin bir göktaşı tarafından vurulmasının yıllık riskinin 17 milyarda bir şans olduğu tahmin edilmektedir, bu da olasılığın yaklaşık 0.00000000006 (6 × 10 −11 ) olduğu ve birkaç trilyonlarca UUID yaratma olasılığına eşit olduğu anlamına gelir. bir yıl içinde ve bir kopyasını alarak. Başka bir deyişle, sadece önümüzdeki 100 yıl için her saniye 1 milyar UUID ürettikten sonra, sadece bir kopya oluşturma olasılığı yaklaşık% 50 olacaktır.

Uyarı:

Bununla birlikte, bu olasılıklar sadece UUID'ler yeterli entropi kullanılarak üretildiğinde geçerlidir. Aksi takdirde, istatistiksel dağılım daha düşük olabileceğinden, kopya olasılığı önemli ölçüde daha yüksek olabilir. Dağıtılmış uygulamalar için benzersiz tanımlayıcıların gerekli olduğu durumlarda, UUID'lerin birçok cihazdan gelen veriler birleştirilse bile çakışmaması için, her cihazda kullanılan tohumların ve jeneratörlerin rastgele olması uygulamanın ömrü boyunca güvenilir olmalıdır. Bunun mümkün olmadığı durumlarda, RFC4122 bunun yerine bir ad alanı varyantı kullanmanızı önerir.

Kaynak: Evrensel olarak benzersiz tanımlayıcılarla ilgili Wikipedia makalesinin Rastgele UUID çoğaltma olasılığı bölümü (bağlantı, bölümü yeniden düzenlemeden önce Aralık 2016'dan itibaren bir revizyona götürür).

Ayrıca, aynı konuyla ilgili aynı evrensel olarak aynı tanımlayıcı makalede Çarpışmalar başlıklı makaleye bakın .


22
Bu bölümü Wikipedia'dan beğendim: Ancak, bu olasılıklar sadece UUID'ler yeterli entropi kullanılarak üretildiğinde geçerlidir. Aksi takdirde, istatistiksel dağılım daha düşük olabileceğinden, kopya olasılığı önemli ölçüde daha yüksek olabilir. Peki, bu cümleyi yinelemenin gerçek şansı nedir. Bilgisayarda gerçek rastgele sayılar oluşturamıyoruz, değil mi?
mans

6
Aslında, çok sayıda çalışma mümkün olduğunca çok sayıda entropi ("gerçek rastgelelik", sanırım onu ​​çağırır) tanıtmak için rastgele sayı API'ları bulmak için gitti. Bkz en.wikipedia.org/wiki/Entropy_%28computing%29
broofa

4
Bu aslında tahmin ettiğimden daha yüksek bir çarpışma olasılığı. Doğum günü paradoksu, sanırım.
Cameron

Bir uygulamanın yürütülmesi arasında UUID kullanmanın güvenli olacağını doğrulayabilir misiniz? (örneğin bir python betiği)
George Sp

büyük örnek ...: D
NuttLoose

151

"Yeterli süre verildiğinde" 100 yıl demek ve bunları saniyede milyar oranında oluşturuyorsanız, evet, 100 yıl sonra% 50 çarpışma şansınız var demektir.


185
Ancak yalnızca bu kimlikler için 256 exabyte depolama alanı kullandıktan sonra.
Bob Aman

16
Komik olan şey, tabii ki akıl almaz tesadüf, şans ve ilahi müdahale seviyelerinde özdeş olan bir satırda 2 üretebilirsiniz, ancak anlaşılmaz oranlara rağmen, hala mümkündür! : D Evet, olmayacak. sadece bir kopya oluşturduğunuzda o anı düşünmenin eğlencesi için! Ekran görüntüsü videosu!
scalabl3

4
Benzersizlik sadece rastgelelik mi? Yoksa başka faktörler var mı? (ör. zaman damgası, ip, vb.)
Weishi Zeng

15
@TheTahaan Rastgele demek değildir. Bu "tamamen öngörülemez" anlamına gelmez - genellikle bir çeşit dağılımı takip ederler. 10 jeton çevirirseniz, 2 kafa, ardından 3 kuyruk ve 5 kafa alma şansı oldukça düşüktür (2 ^ -10, yaklaşık 0.001). Gerçekten rastgele, ama biz kesinlikle olabilir biliyoruz şans farklı bir sonuç alma. Biz sadece olmadığını önceden diyemeyiz edecektir olur.
Richard Rast

5
Sadece bu uygulamanın neyi yanlış yaptığını açıklamak için, benzersizliği için zaman damgası ve mac adresinin bir kombinasyonuna dayanan bir sürüm 1 UUID kullanıyorlar. Bununla birlikte, UUID'leri yeterince hızlı oluşturursanız, zaman damgası henüz artmaz. Bu senaryoda, UUID oluşturma algoritmanızın son kullanılan zaman damgasını izlemesi ve 1 arttırması beklenir. Bu adımı alamadılar. Bununla birlikte, aynı makine tarafından kısa bir süre içinde doğru şekilde üretilen tüm sürüm 1 UUID'ler belirgin benzerlikler gösterecektir, ancak yine de benzersiz olmalıdır.
Bob Aman

103

Birden fazla UUID türü olduğundan, "ne kadar güvenli" kullandığınız türe (UUID spesifikasyonlarının "sürüm" adını verdiği) bağlıdır.

  • Sürüm 1, zamana bağlı artı MAC adresi UUID'dir. 128 bit, ağ kartının MAC adresi (üretici tarafından benzersiz olarak atanır) için 48 bit ve 100 nanosaniye çözünürlüğe sahip 60 bit saat içerir. Bu saat AD 3603'e sarılır, böylece bu UUID'ler en azından o zamana kadar güvenlidir (saniyede 10 milyondan fazla yeni UUID'ye ihtiyacınız yoksa veya birisi ağ kartınızı klonlamazsa). "En azından" diyorum çünkü saat 15 Ekim 1582'de başlıyor, bu yüzden saatin sarılmasından yaklaşık 400 yıl sonra bile küçük bir tekrarlama olasılığı var.

  • Sürüm 4 rasgele sayı UUID'dir. Altı sabit bit vardır ve UUID'nin geri kalanı 122 bit rasgeleliktir. Bir kopyasının ne kadar düşük olduğunu açıklayan Wikipedia'ya veya diğer analizlere bakın .

  • Sürüm 3, MD5'i kullanır ve Sürüm 5, rasgele veya sözde rastgele bir sayı üreteci yerine bu 122 biti oluşturmak için SHA-1'i kullanır. Güvenlik açısından, Sürüm 4'ün istatistiksel bir sorun olması gibidir (özet algoritmasının neyin işlediğinden emin olduğunuz sürece her zaman benzersizdir).

  • Sürüm 2, Sürüm 1'e benzer, ancak daha küçük bir saatle, bu yüzden daha erken sarılır. Ancak Sürüm 2 UUID'ler DCE için olduğundan, bunları kullanmamalısınız.

Böylece tüm pratik problemler için güvenlidirler. Bunu olasılıklara bırakmaktan rahatsızsanız (örneğin, yaşamınız boyunca büyük bir asteroit tarafından yeryüzünün tahrip edilmesinden endişelenen kişi türünüzdür), sadece Sürüm 1 UUID kullandığınızdan emin olun ve benzersiz olduğu garanti edilir ( 3603 AD'den sonra yaşamayı planlamıyorsanız).

Peki neden herkes Versiyon 1 UUID'leri kullanmıyor? Bunun nedeni, Sürüm 1 UUID'lerin oluşturulduğu makinenin MAC adresini ortaya çıkarması ve öngörülebilir olmalarıdır - bu UUID'leri kullanan uygulama için güvenlik etkileri olabilecek iki şey.


1
Sürüm 1 UUID varsayılan olarak aynı sunucu tarafından birçok kişi için oluşturulduğunda ciddi sorunlar yaşıyor. Sürüm 4 UUID benim varsayılanımdır, çünkü herhangi bir dilde veya platformda (javascript dahil) bir tane oluşturmak için hızlıca bir şeyler yazabilirsiniz.
Justin Bozonier

1
@Hoylen Peki açıkladı! ama bu kadar abartı gerekli mi?
Dinoop paloli

1
Teorik olarak , üretici tarafından benzersiz olarak atanır.
OrangeDog

4
Bir kopya ile karşılaşmak için saniyede 10 milyon sürüm 1 UUID üretmek gerekmez; sıra numarasının taşması için tek bir "kene" aralığı içinde sadece 16.384 UUID'lik bir grup üretilmelidir. Bunun, saf bir şekilde, (1) μs düzeyinde tanecikliğe sahip olan ve (2) monotonik olduğu garanti edilmeyen bir saat kaynağına dayanan bir uygulama ile olduğunu gördüm (sistem saatleri yoktur). Kullandığınız UUID oluşturma koduna dikkat edin ve zamana bağlı UUID jeneratörleriyle özellikle dikkatli olun . Doğru olmaları zordur, bu yüzden kullanmadan önce testleri yüklemeye tabi tutun.
Mike Strobel

Oluşturulan v4 UUID'ler arasındaki zaman aralığı daha fazla çarpışma olasılığına yol açabilir mi? Demek istediğim, yoğun bir trafik uygulamasında, aynı anda binlerce uuidin üretildiğini varsayalım, nispeten daha uzun bir süre boyunca aynı miktarda uuid üretilenden daha fazla çarpışma şansı var mı?
Jonathan

18

Bunun cevabı büyük ölçüde UUID sürümüne bağlı olabilir.

Birçok UUID üreticisi, sürüm 4 rasgele bir sayı kullanır. Ancak, bunların birçoğu bunları oluşturmak için Pseudo a Random Number Generator'ı kullanır.

UUID'yi üretmek için küçük bir süre ile zayıf bir şekilde tohumlanmış bir PRNG kullanılırsa, bunun hiç de güvenli olmadığını söyleyebilirim.

Bu nedenle, yalnızca onu oluşturmak için kullanılan algoritmalar kadar güvenlidir.

Flip tarafında, bu soruların cevabını biliyorsanız, bir sürüm 4 uuid kullanmak çok güvenli olması gerektiğini düşünüyorum. Aslında bir ağ blok dosya sistemi üzerindeki blokları tanımlamak için kullanıyorum ve şimdiye kadar bir çatışma olmadı.

Benim durumumda, kullandığım PRNG bir mersenne twister ve / dev / urandom dahil olmak üzere birçok kaynaktan gelen tohumlanma yoluna dikkat ediyorum. Mersenne twister 2 ^ 19937 - 1 periyoduna sahip. Tekrar uuid görmeden önce çok çok uzun bir zaman olacak.


14

Wikipedia'dan alıntı :

Böylece, herkes bir UUID oluşturabilir ve bunu tanımlayıcının asla istemeden başka herhangi bir şey için hiç kimse tarafından kullanılmayacağı konusunda makul bir güvenle tanımlamak için kullanabilir

Aslında ne kadar güvenli olduğu konusunda oldukça iyi detaylar açıklıyor. Sorunuzu cevaplamak için: Evet, yeterince güvenlidir.


9

Diğer cevaplara katılıyorum. UUIDs neredeyse tüm pratik amaçlar için yeterince güvenlidir 1 ve kesinlikle sizin için .

Ama (varsayımsal olarak) olmadıklarını varsayalım.

Bu sorunu hafifletmek için daha iyi bir sistem veya bir model var mı?

İşte birkaç yaklaşım:

  1. Daha büyük bir UUID kullanın. Örneğin, yerine 128 rastgele bit, kullanım 256 veya 512 veya ... Eğer bir tip 4 tarzı eklediğiniz her bit UUID Eğer entropi güvenilir bir kaynak var olduğunu varsayarak, bir yarı yarıya bir çarpışma olasılığını azaltacaktır 2 .

  2. UUID üreten ve şimdiye kadar yayınladığı her birini kaydeden merkezi veya dağıtılmış bir hizmet oluşturun. Yeni bir tane oluşturduğunda, UUID'nin daha önce hiç yayınlanmadığını kontrol eder. Böyle bir hizmet, hizmeti çalıştıran kişilerin kesinlikle güvenilir, bozulmaz, vb. Olduklarını varsayarsak, teknik olarak basit bir yöntem olacaktır. Ne yazık ki, değil ... özellikle hükümetlerin güvenlik örgütlerinin müdahale etme olasılığı olduğunda. Yani, bu yaklaşım muhtemelen pratik değildir ve olabilen 3 gerçek dünyada imkansız.


1 - Eğer UUID'lerin tekliği ülkenizin başkentinde nükleer füzelerin fırlatılıp fırlatılmadığını belirlerse, birçok vatandaşınız "olasılık son derece düşük" diye ikna olmaz. Bu yüzden benim "neredeyse hepsi" kalifikasyonum.

2 - İşte size felsefi bir soru. Gerçekten rastgele bir şey var mı? Değilse nasıl bileceğiz? Bildiğimiz gibi evren bir simülasyon mu? Bir sonucu değiştirmek için fizik kurallarını akla getirebilecek bir Tanrı var mı?

3 - Bu sorunla ilgili herhangi bir araştırma makalesi bilen biri varsa, lütfen yorum yapın.


Sadece 2 numaralı yöntemin temelde UUID kullanımının temel amacını yendiğini ve sadece o noktada klasik bir numaralı kimlik kullanabileceğinizi belirtmek isterim.
Petr Vnenk

Katılmıyorum. Sıralı numaralandırılmış kimliklerdeki kusur, tahmin edilmesi çok kolay olmasıdır. Yöntem 2'yi, UUID'lerin tahmin edilmesini zorlaştıracak şekilde uygulayabilmelisiniz.
Stephen C

8

UUID şemaları genellikle yalnızca sözde rastgele bir öğe değil aynı zamanda geçerli sistem saatini ve varsa ağ MAC adresi gibi genellikle benzersiz bir donanım kimliğini kullanır.

UUID'yi kullanmanın asıl amacı, benzersiz bir kimlik sağlama konusunda kendinizden yapabileceğinizden daha iyi bir iş yapmak için ona güvenmenizdir. Bu, üçüncü bir kriptografi kitaplığı kullanmanın arkasındaki mantıktır. Bunu kendiniz yapmak daha eğlenceli olabilir, ancak bunu yapmak genellikle daha az sorumludur.


6

Yıllardır yapıyoruz. Asla bir sorunla karşılaşmayın.

Genelde benim DB'ler tüm anahtarları ve değiştirilen tarihleri ​​ve benzeri içeren bir tabloya sahip olacak şekilde ayarladım. Hiç yinelenen anahtar sorunu yaşamadım.

Sahip olduğu tek dezavantajı, bazı bilgileri hızlı bir şekilde bulmak için bazı sorgular yazarken, anahtarların çoğunu kopyalayıp yapıştıracağınızdır. Artık hatırlaması kolay kısa kimlikleriniz yok.


5

Eşsizlerini test etmeniz için bir test snippet'i. esinlenerek @ scalabl3 adlı kullanıcının yorumu

Komik olan şey, tabii ki akıl almaz tesadüf, şans ve ilahi müdahale seviyelerinde özdeş olan bir satırda 2 üretebilirsiniz, ancak anlaşılmaz oranlara rağmen, hala mümkündür! : D Evet, olmayacak. sadece bir kopya oluşturduğunuzda o anı düşünmenin eğlencesi için! Ekran görüntüsü videosu! - scalabl3 20 Ekim 15, 19:11

Şanslı hissediyorsanız, onay kutusunu işaretleyin, yalnızca o anda oluşturulan kimlikleri kontrol eder. Bir geçmiş kontrolü istiyorsanız, işaretlenmemiş olarak bırakın. İşaretlemezseniz, bir noktada koçunuz bitebilir. Cpu dostu yapmaya çalıştım, böylece gerektiğinde hızlı bir şekilde iptal edebilirsiniz, sadece snippet'i çalıştır düğmesine tekrar basın veya sayfadan çıkın.

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 Sürüm 1 (tarih-saat ve MAC adresi) UUID ile deneyin.
zaph

Son zamanlarda bir krom güncellemesi olana kadar hızlı yanıp sönüyordu. Aynı şeyi 4 hafta önce fark etmiştim.
Tschallacka


3

UUID4 için, küp şeklinde bir kutuda kenarları 360.000km uzunluğunda kum taneleri olduğu kadar çok kimlik olduğunu düşünüyorum. Bu, Jüpiter'in çapından ~ 2 1/2 kat daha uzun kenarlı bir kutu.

Birilerinin bana birlikleri dağıtıp dağıtmadığımı söyleyebilmesi için çalışıyor:

  • kum tanesi hacmi 0.00947mm ^ 3 ( Guardian )
  • UUID4'ün 122 rastgele biti vardır -> 5.3e36 olası değer ( wikipedia) )
  • o kadar çok kum tanesinin hacmi = 5.0191e34 mm ^ 3 veya 5.0191e + 25m ^ 3
  • bu hacme sahip kübik kutunun yan uzunluğu = 3.69E8m veya 369.000km
  • Jüpiter'in çapı: 139,820km (google)

Aslında sanırım bu% 100 ambalaj varsayıyor, bu yüzden belki bunun için bir faktör eklemeliyim!
kaybetti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.