Наскільки унікальний UUID?


451

Наскільки безпечно використовувати UUID, щоб унікально ідентифікувати щось (я використовую його для файлів, завантажених на сервер)? Як я розумію, це засноване на випадкових числах. Однак мені здається, що даючи достатньо часу, врешті-решт це повториться самотужки, лише випадково Чи є краща система чи модель певного типу, щоб полегшити цю проблему?


11
За досить велике значення "достатньо часу" :)

91
"Наскільки унікальним є UUID?" Універсально унікальний, я вважаю. ;)
Майлз

29
І якщо ви не плануєте розвиватися на Венері, GUID повинен бути достатнім.
скафман

1
Більше деталей та генератор тут: онлайн uuid генератор
Дейв

2
"унікальний" засіб ніколи не стикається . Якщо він має потенціал до зіткнення, це не є унікальним . Отже, за визначенням, UUID не є унікальним та безпечним лише у тому випадку, якщо ви готові до потенційних зіткнень незалежно від випадків зіткнення. В іншому випадку ваша програма просто неправильна. Ви можете сказати UUID як "майже унікальний", але це не означає, що він "унікальний".
Еоніл

Відповіді:


446

Дуже безпечно:

щорічний ризик ураження даною людиною метеориту оцінюється як один шанс у 17 мільярдів, що означає, що ймовірність становить приблизно 0,00000000006 (6 × 10 −11 ), що еквівалентно шансам створення декількох десятків трильйонів UUID через рік і маючи один дублікат. Іншими словами, лише після генерування 1 мільярда UUID щосекунди протягом наступних 100 років ймовірність створення лише одного дубліката становила б приблизно 50%.

Caveat:

Однак ці ймовірності мають місце лише тоді, коли UUID згенеровано за допомогою достатньої ентропії. Інакше ймовірність дублікатів може бути значно більшою, оскільки статистична дисперсія може бути нижчою. Якщо для розподілених додатків потрібні унікальні ідентифікатори, щоб UUID не стикалися навіть при злитті даних з багатьох пристроїв, випадковість насіння та генераторів, які використовуються на кожному пристрої, повинна бути надійною протягом життя програми. Якщо це неможливо, RFC4122 рекомендує замість цього використовувати варіант простору імен.

Джерело: Імовірність випадкових UUID дублікатів статті Вікіпедії про універсальні унікальні ідентифікатори (посилання призводить до перегляду з грудня 2016 року, перш ніж редагування переробило розділ).

Також дивіться поточний розділ з тієї самої теми в тій же статті Універсального унікального ідентифікатора, Collisions .


22
Мені подобається ця частина з Вікіпедії: Однак ці ймовірності зберігаються лише тоді, коли UUID згенеровано за допомогою достатньої ентропії. Інакше ймовірність дублікатів може бути значно більшою, оскільки статистична дисперсія може бути нижчою. Тож, який реальний шанс повторити це речення. Ми не можемо створити реальні випадкові числа на комп’ютері, чи не можемо?
mans

6
Насправді багато роботи було спрямовано на пошук способів ввести якомога більше ентропії ("реальної випадковості", я думаю, ви б це назвали) в API випадкових чисел. Дивіться en.wikipedia.org/wiki/Entropy_%28computing%29
брофа

4
Це насправді більша ймовірність зіткнення, ніж я уявляв. Парадокс від дня народження, напевно.
Камерон

Чи можете ви підтвердити, що використання UUID було б безпечним між виконанням програми? (наприклад, сценарій пітона)
George Sp

чудовий приклад ...: D
NuttLoose

151

Якщо під «даним достатньо часу» ви маєте на увазі 100 років, і ви створюєте їх зі швидкістю мільярд в секунду, то так, ви маєте 50% шансів зіткнутись через 100 років.


185
Але лише після використання 256 екбабітів пам’яті для цих ідентифікаторів.
Боб Аман

16
Найсмішніше, що ти можеш генерувати 2 підряд, які були однаковими, звичайно, при розумних рівнях збігу, удачі та божественного втручання, але, незважаючи на незрівнянні шанси, все-таки можливо : D Так, цього не станеться. просто кажу про розвагу думати про той момент, коли ти створив дублікат! Скріншот відео!
scalabl3

4
Є унікальність виключно через випадковість? Або є інші фактори? (наприклад, штамп часу, ip тощо)
Weishi Zeng

15
@TheTahaan Це не те, що означає випадкові. Це не означає "абсолютно непередбачуваний" - зазвичай вони дотримуються певного розподілу. Якщо ви перевернете 10 монет, шанс отримати 2 голови, а потім 3 хвости, а потім 5 голів, досить низький (2 ^ -10, приблизно 0,001). Це справді випадково, але ми абсолютно можемо знати шанс отримати певний результат. Ми просто не можемо сказати заздалегідь , буде це буде відбуватися.
Річард Раст

5
Просто для пояснення того, що ця реалізація зробила неправильно, вони використовують UUID версії 1, яка для своєї унікальності покладається на поєднання часової позначки та mac-адреси. Однак якщо ви генеруєте UUID досить швидко, часова мітка ще не зростає. У цьому випадку ваш алгоритм генерації UUID повинен відслідковувати останню використану мітку часу та збільшувати її на 1. Вони явно не змогли зробити цей крок. Однак усі UUID версії 1, правильно згенеровані однією і тією ж машиною за короткий період, виявлятимуть очевидні подібності, але вони все одно повинні бути унікальними.
Боб Аман

103

Існує більше одного типу UUID, тому "наскільки безпечно" залежить від того, який тип (який специфікації UUID називають "версією") ви використовуєте.

  • Версія 1 - час, заснований на MAC-адресі UUID. 128-біт містить 48 біт для MAC-адреси мережевої картки (яка однозначно призначена виробником) та 60-бітний годинник з роздільною здатністю 100 наносекунд. Цей годинник завершується в 3603 році нашої ери, щоб ці UUID були безпечними принаймні до цього часу (якщо вам не потрібно більше 10 мільйонів нових UUID за секунду або хтось клонує вашу мережеву карту). Я кажу "принаймні", оскільки годинник починається з 15 жовтня 1582 року, тож у вас є приблизно 400 років після обгортання годинника, перш ніж є навіть невелика можливість дублювання.

  • Версія 4 - випадкове число UUID. Там шість фіксованих біт, а решта UUID - 122-біт випадковості. Див. Вікіпедію чи інший аналіз, який описує, наскільки дуже маловірочним є дублікат.

  • Версія 3 використовує MD5, а версія 5 використовує SHA-1 для створення цих 122-бітних замість генератора випадкових чи псевдовипадкових чисел. Так що з точки зору безпеки, це схоже на версію 4, що є статистичною проблемою (якщо ви впевнені, що алгоритм дайвінгу обробляє завжди унікальним).

  • Версія 2 схожа на версію 1, але з меншим годинником, тому вона збирається набагато швидше. Але оскільки UUID версії 2 призначені для DCE, ви не повинні їх використовувати.

Тож для всіх практичних проблем вони безпечні. Якщо вам незручно залишати це до ймовірностей (наприклад, це тип людини, яка переживає за те, що земля зруйнується великим астероїдом за все життя), просто переконайтеся, що ви використовуєте UUID версії 1, і він гарантовано буде унікальним ( у вашому житті, якщо ви не плануєте прожити минуле 3603 року нашої ери).

То чому не всі просто використовують UUID версії 1? Це тому, що UUID версії 1 розкривають MAC-адресу машини, на якій він був створений, і вони можуть бути передбачуваними - дві речі, які можуть мати наслідки для безпеки програми, використовуючи ці UUID.


1
Дефолт до версії 1 UUID має серйозні проблеми, коли вони створюються одним і тим же сервером для багатьох людей. Версія 4 UUID є моїм замовчуванням, оскільки ви можете швидко написати щось для створення цього на будь-якій мові чи платформі (включаючи JavaScript).
Джастін Бозоньє

1
@Hoylen Добре пояснив! але чи потрібно це велике перебільшення?
Dinoop paloli

1
Теоретично це однозначно призначається виробником.
OrangeDog

4
Не потрібно генерувати 10 мільйонів UUID версії 1 за секунду, щоб зустріти дублікат; потрібно просто генерувати партію 16 384 UUID в межах проміжку однієї "галочки", щоб переповнити порядковий номер. Я бачив, що це відбувається з реалізацією, яка наївно покладалася на тактове джерело, яке (1) має м ясність рівня мкс, і (2) не було гарантовано монотонним (системні годинники не є). Будьте уважні, чий код генерації UUID ви використовуєте, і будьте особливо обережні з генераторами UUID, заснованими на часі. Їх важко отримати правильно, тому піддайте їх тестуванню перед завантаженням .
Майк Стробель

Чи може часовий проміжок між згенерованими U4 UUID призвести до збільшення ймовірностей зіткнення? Я маю на увазі, що у великому застосуванні дорожнього руху, припустимо, одночасно генеруються тисячі уйдів, чи більше шансів на зіткнення, ніж якщо б однакова кількість удуїдів генерувалася протягом відносно більшого періоду часу?
Джонатан

18

Відповідь на це може багато в чому залежати від версії UUID.

Багато генераторів UUID використовують випадкове число версії 4. Однак багато хто з них використовує псевдогенератор випадкових чисел для їх генерації.

Якщо для генерування UUID використовується погано насіннєвий PRNG з невеликим періодом, я б сказав, що це зовсім не безпечно.

Тому це так само безпечно, як алгоритми, що використовуються для його створення.

З іншого боку, якщо ви знаєте відповідь на ці питання, я вважаю, що версія 4 uuid повинна бути дуже безпечною для використання. Насправді я використовую його для ідентифікації блоків у файловій системі мережевого блоку, і до цього часу не було зіткнення.

У моєму випадку PRNG, який я використовую, є трістером мерсена, і я обережно ставлюся до того, як його висівають, з різних джерел, включаючи / dev / urandom. Мерсенн твістер має період 2 ^ 19937 - 1. Мине дуже багато часу, перш ніж я побачу повторний ууїд.


14

Цитування з Вікіпедії :

Таким чином, кожен може створити UUID і використовувати його для ідентифікації чогось з розумною впевненістю, що ідентифікатор ніколи не буде ненавмисно використовуватися ким-небудь для чого-небудь іншого

Він продовжує пояснювати досить добре детально про те, наскільки це насправді безпечно. Отже, щоб відповісти на ваше запитання: Так, це досить безпечно.


9

Я погоджуюся з іншими відповідями. UUID є безпечними для практично всіх практичних цілей 1 , і, звичайно, для ваших.

Але припустимо (гіпотетично), що це не так.

Чи є краща система чи модель певного типу, щоб полегшити цю проблему?

Ось пара підходів:

  1. Використовуйте більший UUID. Наприклад, замість 128 випадкових біт використовуйте 256 або 512 або ... Кожен біт, який ви додаєте до UUID стилю типу-4, зменшить вдвічі ймовірність зіткнення, припускаючи, що у вас є надійне джерело ентропії 2 .

  2. Створіть централізовану або розподілену службу, яка генерує UUID та записує всі, що були видані. Кожен раз, коли він генерує новий, він перевіряє, що UUID ніколи раніше не був виданий. Таку послугу технічно було б реально реалізувати (я думаю), якби ми припустили, що люди, які керують цією послугою, були абсолютно надійними, нетлінні та ін. На жаль, їх немає ... особливо коли є можливість врядових організацій безпеки втручатися. Отже, такий підхід, мабуть, недоцільний, а в реальному світі може бути 3 неможливим.


1 - Якби унікальність UUID визначала, чи будуть ядерні ракети запускатись у столиці вашої країни, багато ваших співгромадян не будуть переконані "ймовірність надзвичайно низька". Звідси моя «майже вся» кваліфікація.

2 - А ось вам філософське питання. Чи є що-небудь справді випадковим? Як ми могли б знати, якби цього не було? Чи є Всесвіт, як ми знаємо, це моделювання? Чи є Бог, який, можливо, може «підправити» закони фізики, щоб змінити результат?

3 - Якщо хтось знає якісь наукові роботи з цієї проблеми, будь ласка, прокоментуйте.


Я просто хочу зазначити, що метод №2 в основному перемагає основну мету використання UUID, і ви можете також просто використовувати класичний нумерований ідентифікатор в цьому пункті.
Петро Вненк

Я не погоджуюсь. Недолік послідовних пронумерованих ідентифікаторів полягає в тому, що їх занадто легко здогадатися. Ви повинні мати можливість реалізувати метод 2 таким чином, що UUID не може здогадатися.
Стівен С

8

У схемах UUID зазвичай використовується не тільки псевдовипадковий елемент, але і поточний системний час, і якийсь часто унікальний ідентифікатор обладнання, якщо він є, наприклад, мережева MAC-адреса.

Вся суть використання UUID полягає в тому, що ви довіряєте йому зробити кращу роботу з надання унікального ідентифікатора, ніж ви самі могли б зробити. Це те саме обґрунтування використання сторонньої бібліотеки криптографії, а не прокатування власної. Робити це самостійно може бути веселіше, але зазвичай це менш відповідально.


6

Робили це роками. Ніколи не стикайтеся з проблемою.

Зазвичай я встановлюю свої БД, щоб мати одну таблицю, яка містить усі ключі та модифіковані дати та інше. Ніколи не стикався з проблемою копій ключів.

Єдиний недолік, який він має, коли ви пишете якісь запити, щоб швидко знайти якусь інформацію, ви робите багато копіювання та вставлення ключів. У вас більше немає короткого простого запам'ятовування ідентифікаторів.


5

Ось фрагмент тестування для перевірки унікальності. натхненний коментарем @ scalabl3

Найсмішніше, що ти можеш генерувати два підряд, які були однаковими, звичайно, при розумних рівнях збігу, удачі та божественного втручання, але, незважаючи на незрівнянні шанси, все-таки це можливо! : D Так, цього не станеться. просто кажу про розвагу думати про той момент, коли ти створив дублікат! Скріншот відео! - scalabl3 20 жовтня 15 о 19:11

Якщо вам пощастило, поставте прапорець, він перевіряє лише створені наразі ідентифікатори. Якщо ви хочете перевірити історію, залиште його без позначення. Зауважте, у вас може у якийсь момент закінчитися баран, якщо залишити його без галочки. Я спробував зробити це чіткішим для процесора, щоб ви могли швидко перервати роботу, якщо потрібно, просто натисніть кнопку запуску фрагменту знову або залиште сторінку.

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/>


Спробуйте з UUID RFC 4122 версії 1 (дата-час та MAC-адреса).
зап

Раніше вона палала швидко, до недавнього часу оновлення хрому. Я це помітив 4 тижні тому.
Цаллацька

3

Я не знаю, чи це має значення для вас, але майте на увазі, що GUID є унікальними в усьому світі, але підрядки GUID не є .


1
Майте на увазі, що посилання, пов'язане тут, говорить про UUID версії 1 (які беруть інформацію про генеруючий комп'ютер тощо в ідентифікатор). Більшість інших відповідей говорять про версію 4 (які є абсолютно випадковими). Вищенаведена стаття Wikipedia en.wikipedia.org/wiki/Universally_unique_identifier пояснює різні види UUID.
kratenko

3

Для UUID4 я вважаю, що в кубоподібній коробці зі сторонами завдовжки 360 000 км є приблизно стільки ідентифікаторів, скільки є зерна піску. Це коробка зі сторонами ~ 2 1/2 рази довше діаметра Юпітера.

Працюючи, щоб хтось міг сказати мені, чи я заплутав одиниці:

  • об'єм зерна піску 0,00947мм ^ 3 ( Guardian )
  • UUID4 має 122 випадкових біта -> 5.3e36 можливих значень ( wikipedia )
  • об'єм цієї кількості піску = 5,0191e34 мм ^ 3 або 5,0191е + 25м ^ 3
  • довжина сторони кубічної коробки з цим об'ємом = 3,69 Е8м або 369 000км
  • діаметр Юпітера: 139 820 км (google)

Насправді я думаю, що це передбачає 100% упаковку, тому, можливо, я повинен додати фактор для цього!
програв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.