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

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

10 ответов


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

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

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

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

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

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


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


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

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

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

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

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

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

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


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

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

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

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

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

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


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

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

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


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

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


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

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

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


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

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

Если Вам ПОВЕЗЕТ, установите флажок, он проверяет только текущие сгенерированные идентификаторы. Если вы хотите проверить историю, оставьте ее непроверенной. Обратите внимание, что в какой-то момент у вас может закончиться ОЗУ, если вы оставите его непроверенным. Я попытался сделать его CPU дружественным, чтобы вы могли быстро прервать, когда это необходимо, просто нажмите кнопку 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/>

Я не знаю, имеет ли это значение для вас, но имейте в виду, что GUID являются глобально уникальными, но подстроки GUID не являются.


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

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

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

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

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

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


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

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

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