Насколько уникален UUID?


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

10 323

10 ответов:

очень безопасный:

ежегодный риск попадания метеорита в человека составляет оценивается как один шанс из 17 миллиардов, что означает, что вероятность составляет около 0,00000000006 (6 × 10-11), эквивалентные коэффициентам создание нескольких десятков триллионов Уид в год и наличие одного дубликат. Другими словами, только после генерации 1 миллиарда UUIDs каждый во-вторых, в течение следующих 100 лет вероятность создания только одного дубликат будет около 50%.

предостережение:

однако эти вероятности сохраняются только тогда, когда генерируются UUIDs используя достаточную энтропию. В противном случае, вероятность дубликатов может быть значительно выше, поскольку статистический разброс может быть ниже. Где для распространения требуются уникальные идентификаторы приложения, так что UUIDs не конфликтуют даже тогда, когда данные из многих приборы слиты, случайность семян и генераторов используемых дальше каждый устройство должно быть надежным в течение всего срока службы приложения. Где это невозможно, RFC4122 рекомендует использовать вариант пространства имен вместо.

Источник: The случайная вероятность UUID дубликатов раздел статьи Википедии об универсально уникальных идентификаторах (ссылка приводит к пересмотру с декабря 2016 года до редактирования переработанного раздела).

Также см. текущий раздел по той же теме на том же универсальном уникальный идентификатор статьи,конфликты.

Если под "заданным временем" вы подразумеваете 100 лет, и вы создаете их со скоростью миллиард в секунду, то да, у вас есть 50% шанс на столкновение через 100 лет.

существует более одного типа UUID, поэтому "насколько безопасно" зависит от того, какой тип (который спецификации UUID называют "версия") вы используете.

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

  • версия 4-это случайное число UUID. Есть шесть фиксированных битов, а остальная часть UUID-это 122 бита случайности. Смотрите Википедия или другой анализ, который описывает, как очень маловероятно дубликат есть.

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

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

Так что для всех практических задач они безопасны. Если вам неудобно оставлять его до вероятностей (например, ваш тип человека беспокоится о том, что Земля будет уничтожена большим астероидом в вашей жизни), просто убедитесь, что вы используете версию 1 UUID, и она гарантированно будет уникальной (в вашей жизни, если вы не планируете жить после 3603 года н. э.).

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

ответ на это может во многом зависеть от версии UUID.

многие генераторы UUID используют случайное число версии 4. Однако, многие из них используют псевдо генератор случайных чисел для их создания.

Если для генерации UUID используется плохо засеянный PRNG с небольшим периодом, я бы сказал, что это не очень безопасно.

таким образом, это только так безопасно, как алгоритмы, используемые для генерации.

с другой стороны, если вы знаете ответы на эти вопросы тогда я думаю, что версия 4 uuid должна быть очень безопасной в использовании. На самом деле я использую его для идентификации блоков в файловой системе сетевого блока и до сих пор не сталкивался.

в моем случае PRNG, который я использую, является Mersenne twister, и я осторожен с тем, как он посеян, который из нескольких источников, включая /dev/urandom. Мерсенн твистер имеет период 2^19937 - 1. Пройдет очень много времени, прежде чем я увижу повторение uuid.

цитирую Википедия:

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

Он продолжает объяснять довольно подробно о том, насколько это безопасно на самом деле. Поэтому, чтобы ответить на ваш вопрос: Да, это достаточно безопасно.

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

весь смысл использования UUID заключается в том, что Вы доверяете ему делать лучшую работу по предоставлению уникального идентификатора, чем вы сами могли бы сделать. Это то же самое обоснование использования сторонней криптографической библиотеки, а не сворачивание собственной. Делать это самостоятельно может быть веселее, но это как правило, менее ответственно это делать.

делали это в течение многих лет. Никогда не сталкивайтесь с проблемой.

Я обычно настраиваю свою БД, чтобы иметь одну таблицу, содержащую все ключи и измененные даты и т. д. Никогда не сталкивался с проблемой дубликатов ключей.

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

вот фрагмент тестирования для вас, чтобы проверить это uniquenes. вдохновленный комментарием @scalabl3

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

Если вы чувствуете себя счастливым, проверьте флажок, он только проверяет в настоящее время генерируется идентификатор. Если вы хотите проверить историю, оставьте его неотмеченным. Обратите внимание, что в какой-то момент у вас может закончиться ОЗУ, если вы оставите его непроверенным. Я попытался сделать его дружественным к процессору, чтобы вы могли быстро прервать его, когда это необходимо, просто снова нажмите кнопку run snippet или покиньте страницу.

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

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

но предположим (гипотетически), что это не так.

есть ли лучшая система или шаблон какого-то типа, чтобы облегчить эту проблему?

вот несколько подходов:

  1. используйте больший UUID. Например, вместо 128 случайных битов используйте 256 или 512 или ... Каждый бит, который вы добавляете в UUID типа 4, уменьшит вероятность столкновения наполовину, предполагая, что у вас есть надежный источник энтропии2.

  2. создайте централизованную или распределенную службу, которая генерирует UUIDs и записывает все, что она когда-либо выпускала. Каждый раз, когда он генерирует новый, он проверяет, что UUID никогда не был выпущен раньше. Такая услуга была бы технически прямолинейной для реализации (я думаю) , если бы мы предположили, что люди, управляющие службой, были абсолютно надежными, неподкупными и т. д. К сожалению, это не так ... особенно когда есть возможность вмешательства правительств. Таким образом, этот подход, вероятно, непрактичен, и может быть3 невозможно в реальном мире.


1-Если бы уникальность UUIDs определила, были ли запущены ядерные ракеты в столице вашей страны, многие ваши сограждане не были бы убеждены по "вероятность крайне низкая". Отсюда и моя квалификация "почти все".

2 - и вот вам философский вопрос. Есть ли что-нибудь действительно случайное? Как бы мы узнали, если бы это было не так? Является ли Вселенная, какой мы ее знаем, симуляцией? Есть ли Бог, который мог бы предположительно "настроить" законы физики, чтобы изменить результат?

3 - Если кто-нибудь знает о каких-либо научных работах по этой проблеме, пожалуйста, прокомментируйте.