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

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

Ответ 1

Очень безопасно:

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

Цитата из Wikipedia:

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

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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

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

Если вам повезет, установите флажок, он проверяет только текущие идентификаторы. Если вы хотите проверить историю, оставьте ее непроверенной. Обратите внимание, что в какой-то момент у вас может не хватать барана, если вы оставите его непроверенным. Я попытался сделать его дружественным 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 <[email protected]>, 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 <[email protected]>, 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/>

Ответ 9

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

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

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

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

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

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


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

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

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