UUIDはどのくらいユニークですか?


451

UUIDを使用して何かを一意に識別することはどの程度安全ですか(サーバーにアップロードされたファイルに使用しています)?私が理解しているように、それは乱数に基づいています。しかし、十分な時間を与えられれば、それは最終的には、たまたま純粋に偶然にも繰り返されるように思えます。この問題を軽減するためのより良いシステムまたは何らかのタイプのパターンはありますか?


11
「十分な時間」の十分に大きな値の場合:)

91
「UUIDはどのくらいユニークですか?」普遍的にユニークだと思います。;)
マイル

29
そして、金星での開発を計画していない限り、GUIDで十分です。
skaffman 2009

1
詳細は、ここで発電機:オンラインUUIDジェネレータ
デイブ・

2
「ユニーク」とは、衝突しないことを意味します。衝突する可能性がある場合、それは一意ではありません。したがって、定義上、UUIDは一意ではなく、衝突の可能性に関係なく潜在的な衝突に備える場合にのみ安全です。そうでない場合、プログラムは単に正しくありません。UUIDは「ほぼ一意」と言えますが、「一意」であるとは限りません。
Eonil

回答:


444

非常に安全:

隕石に当たる特定の人の年間リスクは、170億回に1回の確率と推定されます。つまり、確率は約0.00000000006(6×10 -11)であり、数十兆のUUIDを作成する確率に相当します。 1年で、1つの複製があります。つまり、今後100年間、毎秒10億個のUUIDを生成した後にのみ、複製が1つだけ作成される確率は約50%になります。

警告:

ただし、これらの確率は、十分なエントロピーを使用してUUIDが生成された場合にのみ保持されます。そうしないと、統計的分散が低くなる可能性があるため、重複の可能性が大幅に高くなる可能性があります。多くのデバイスからのデータがマージされてもUUIDが競合しないように、分散アプリケーションに一意の識別子が必要な場合、すべてのデバイスで使用されるシードとジェネレーターのランダム性は、アプリケーションの存続期間中信頼できる必要があります。これが実行できない場合、RFC4122は代わりに名前空間バリアントを使用することを推奨します。

出典:ユニバーサルユニーク識別子に関するWikipediaの記事のランダムなUUIDの重複セクション(リンクは、セクションを再編集する前の2016年12月の改訂にリンクしています)。

また、同じ普遍的に一意の識別子に関する記事Collisionsの同じ主題に関する現在のセクションも参照してください。


22
ウィキペディアのこの部分が好きです。しかし、これらの確率は、十分なエントロピーを使用してUUIDが生成された場合にのみ保持されます。そうしないと、統計的分散が低くなる可能性があるため、重複の可能性が大幅に高くなる可能性があります。それで、この文に注意して重複する本当のチャンスは何ですか。コンピューターで実際の乱数を作成することはできませんか?
2014

6
実際、乱数APIにできる限り多くのエントロピー(「本当のランダム性」と呼んでいると思います)を導入する方法を見つけるために、多くの作業が行われています。en.wikipedia.org/wiki/Entropy_%28computing%29
broofa '12 / 12/06

4
それは実際に私が想像したよりも高い衝突の確率です。誕生日のパラドックスだと思います。
Cameron

アプリケーションの実行間でUUIDを使用しても安全であることを確認できますか?(例:pythonスクリプト)
George Sp

素晴らしい例...:D
NuttLoose 2018年

151

「十分な時間を与えられた」とは、100年を意味し、1秒あたり10億の割合でそれらを作成している場合、はい、100年後に衝突が発生する可能性は50%です。


185
ただし、これらのIDに最大256エクサバイトのストレージを使用した後にのみ。
ボブアマン

16
面白いことに、偶然、運、神聖な介入という驚異的なレベルで、同じ2行を連続して生成できますが、信じられないほどのオッズにもかかわらず、それはまだ可能です!:Dはい、それは起こりません。複製を作成したその瞬間について考えるのは面白そうです。スクリーンショットビデオ!
scalabl3 2015年

4
一意性は純粋にランダム性によるものですか?または他の要因がありますか?(タイムスタンプ、IPなど)
Weishi Zeng

15
@TheTahaanランダムという意味ではありません。「まったく予測できない」という意味ではありません-通常、それらはある種の分布に従います。10枚のコインを投げると、2つの表が出て、その後に3つの尾が続き、その後に5つの表が出る確率はかなり低くなります(2 ^ -10、約0.001)。それは真にランダムだが、我々は絶対にすることができます知っているチャンス特定の結果を得るのを。それ起こるかどうかを前もって言うことはできません。
Richard Rast

5
この実装が間違ったことを説明するためだけに、バージョン1のUUIDを使用しています。このUUIDは、一意性をタイムスタンプとMACアドレスの組み合わせに依存しています。ただし、UUIDを十分に速く生成した場合、タイムスタンプはまだインクリメントされていません。このシナリオでは、UUID生成アルゴリズムは、最後に使用されたタイムスタンプを追跡し、1ずつインクリメントすることになっています。それらは明らかにそのステップを踏むことに失敗しました。ただし、同じマシンによって短期間に正しく生成されたすべてのバージョン1 UUIDは明らかな類似性を示しますが、依然として一意である必要があります。
Bob Aman 2017

103

UUIDには複数のタイプがあるため、「安全性」は、使用しているタイプ(UUID仕様では「バージョン」と呼ばれています)によって異なります。

  • バージョン1は、時間ベースおよびMACアドレスUUIDです。128ビットには、ネットワークカードのMACアドレス(製造元によって一意に割り当てられます)用の48ビットと、100ナノ秒の分解能を持つ60ビットクロックが含まれています。そのクロックは3603 ADでラップするため、これらのUUIDは少なくともそれまで安全です(1秒あたり1000万を超える新しいUUIDが必要な場合や、誰かがネットワークカードのクローンを作成する場合を除きます)。「少なくとも」と言うのは、時計が1582年10月15日に始まるため、時計がラップしてから400年ほど経ってから、重複の可能性が少しでもあるからです。

  • バージョン4は乱数UUIDです。6つの固定ビットがあり、残りのUUIDは122ビットのランダム性です。ウィキペディアまたはその他の分析を参照して、重複の可能性が非常に低いことを説明します。

  • バージョン3はMD5を使用し、バージョン5はランダムまたは疑似乱数ジェネレータの代わりにSHA-1を使用してこれらの122ビットを作成します。したがって、安全性の点では、バージョン4が統計的な問題であるようです(処理するダイジェストアルゴリズムが常に一意であることを確認する限り)。

  • バージョン2はバージョン1に似ていますが、クロックが小さいため、より早く循環します。ただし、バージョン2のUUIDはDCE用であるため、これらを使用しないでください。

したがって、すべての実用的な問題について、それらは安全です。確率に任せたくない場合(たとえば、生涯で地球が大きな小惑星によって破壊されるのを心配している人の場合)、バージョン1のUUIDを使用していることを確認してください。あなたの生涯において、あなたが3603 ADを過ぎて生きることを計画していない限り)。

では、なぜ誰もが単にバージョン1のUUIDを使用しないのですか?これは、バージョン1のUUIDが、それが生成されたマシンのMACアドレスを明らかにし、それらが予測可能になる可能性があるためです。


1
バージョン1のUUIDにデフォルト設定すると、同じサーバーによって多くの人のために生成された場合、重大な問題が発生します。バージョン4のUUIDが私のデフォルトです。これは、何かをすばやく記述して、任意の言語またはプラットフォーム(javascriptを含む)で生成することができるためです。
ジャスティンボゾニエ2013

1
@Hoylenよく説明されました!しかし、これだけの誇張が必要ですか?
Dinoop paloli 2014

1
理論的には、メーカーによって一意に割り当てられます。
OrangeDog 2015年

4
重複に遭遇するために、1秒間に1000万のバージョン1 UUIDを生成する必要はありません。シーケンス番号をオーバーフローさせるには、単一の「ティック」の範囲内で16,384個のUUIDのバッチを生成するだけです。これは、単純に、(1)μsレベルの粒度を持つクロックソースに依存する実装で発生し、(2)単調であることが保証されていません(システムクロックはそうではありません)。使用するUUID生成コードに注意、時間ベースのUUIDジェネレーターには特に注意してください。それらを正しく行うのは難しいため、使用する前に負荷テストを行ってください。
マイクストロベル2017年

生成されたv4 UUID間の期間は、より多くの衝突確率につながる可能性がありますか?交通量の多いアプリケーションでは、何千ものuuidが同時に生成されると仮定すると、比較的長い時間にわたって同じ量のuuidが生成された場合よりも、衝突の可能性が高くなりますか?
ジョナサン

18

これに対する答えは、主にUUIDバージョンに依存する場合があります。

多くのUUIDジェネレーターは、バージョン4の乱数を使用します。ただし、これらの多くは乱数生成器の疑似を使用して生成します。

シードが不十分で期間が短いPRNGを使用してUUIDを生成する場合、それは非常に安全ではないと言えます。

したがって、それを生成するために使用されるアルゴリズムと同じくらい安全です。

反対に、これらの質問に対する答えがわかっている場合は、バージョン4のuuidを使用しても安全だと思います。実際、私はネットワークブロックファイルシステム上のブロックを識別するために使用しており、これまでのところ衝突はありません。

私の場合、私が使用しているPRNGはメルセンヌツイスターであり、/ dev / urandomを含む複数のソースからシードされる方法に注意しています。メルセンヌツイスターの周期は2 ^ 19937 − 1です。繰り返しのUUIDが表示されるまでには、非常に長い時間がかかります。


14

ウィキペディアからの引用:

したがって、誰でもUUIDを作成し、それを使用して、識別子が他の目的で誰かによって意図せずに使用されることはないという合理的な自信を持って何かを識別することができます。

それが実際にどれほど安全であるかについてかなり詳細に説明し続けます。だからあなたの質問に答える:はい、それは十分に安全です。


9

私は他の答えに同意します。UUIDは、ほぼすべての実用的な目的に対して十分に安全です1でであり、確かにです。

しかし、(仮説的に)そうではないと仮定します。

この問題を軽減するためのより良いシステムまたは何らかのタイプのパターンはありますか?

ここにいくつかのアプローチがあります:

  1. より大きいUUIDを使用してください。たとえば、128のランダムビットの代わりに、256または512または...を使用します。タイプ4スタイルのUUIDに追加する各ビットは、信頼性の高いエントロピーソースがあると仮定して、衝突の確率を半分にします2

  2. UUIDを生成し、これまでに発行したすべてのサービスを記録する、集中型または分散型のサービスを構築します。新しいものを生成するたびに、UUIDが発行されたことがないことを確認します。そのようなサービスは、サービスを実行している人々が完全に信頼できる、腐敗しない、などと仮定すれば、技術的に簡単に実装できます(私はそう思います)。残念ながら、そうではありません...特に政府のセキュリティ組織が干渉する可能性がある場合はそうです。だから、このアプローチは、おそらく現実的ではない、あってもよい3現実の世界では不可能。


1-核ミサイルが自国の首都で発射されたかどうかがUUIDの一意性によって決定された場合、多くの仲間の市民は「確率が非常に低い」と確信していません。したがって、私の「ほぼすべて」の資格。

2-そしてここにあなたのための哲学的質問があります。本当にランダムなものはありますか?そうでない場合はどうすればわかりますか?私たちが知っている宇宙はシミュレーションですか?結果を変えるために物理法則を「微調整」する可能性がある神はいますか?

3-この問題に関する研究報告を誰かが知っている場合は、コメントしてください。


メソッド番号2は基本的にUUIDを使用する主な目的に反することを指摘したいのですが、その時点でクラシック番号付きIDを使用することもできます。
Petr Vnenk

同意しません。連番IDの欠点は、簡単に推測できないことです。UUIDを推測しにくくする方法でメソッド2を実装できるはずです。
スティーブンC

8

UUIDスキームは一般に、疑似ランダム要素だけでなく、現在のシステム時刻、およびネットワークMACアドレスなど、使用可能な場合はある種のしばしば一意のハードウェアIDも使用します。

UUIDを使用する重要な点は、ユーザー自身ができるよりも、一意のIDを提供するという点で信頼できるということです。これは、独自の暗号化ライブラリを使用するのではなく、サードパーティの暗号化ライブラリを使用するのと同じ理由です。自分で行う方が楽しいかもしれませんが、通常はそうする責任はありません。


5

何年もやってきた。問題が発生することはありません。

私は通常、すべてのキーと変更された日付などを含む1つのテーブルを持つようにDBを設定します。重複キーの問題に遭遇したことはありません。

唯一の欠点は、いくつかのクエリを記述していくつかの情報をすばやく見つけるときに、キーのコピーと貼り付けを頻繁に行うことです。覚えやすい短いIDはもうありません。


5

一意性をテストするためのテストスニペットを次に示します。@ scalabl3のコメントに触発されました

おもしろいことに、偶然、運、神の介入という驚異的なレベルで、同じ2行を続けて生成することができます。:Dはい、それは起こりません。複製を作成したその瞬間について考えるのは面白そうです。スクリーンショットビデオ!– scalabl3 2015年10月20日19:11

運が良ければ、チェックボックスをチェックしてください。現在生成されているIDのみがチェックされます。履歴チェックを希望する場合は、チェックしないでください。チェックを外したままにすると、いつかRAMが不足する可能性があることに注意してください。私はそれを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 <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バージョン1(日時およびMACアドレス)UUIDを試してください。
zaph

以前は、最近のクロムの更新まで、非常に高速でした。私は4週間前に同じことに気づきました。
Tschallacka 2017年

3

これが重要かどうかはわかりませんが、GUIDはグローバルに一意ですが、GUIDのサブストリングはそうではないことに注意してください。


1
ここにリンクされているリファレンスは、バージョン1のUUID(生成するコンピューターなどに関する情報をIDに取り込む)について述べていることに注意してください。他のほとんどの回答はバージョン4について話します(完全にランダムです)。上記のリンクされたウィキペディアの記事en.wikipedia.org/wiki/Universally_unique_identifierは、さまざまな種類のUUIDを説明しています。
kratenko 14

3

UUID4の場合、辺の長さが360,000 kmの立方体の箱に砂の粒があるのとほぼ同じ数のIDがあるようにします。これは、ジュピターの直径の約2 1/2倍の長さの辺を持つボックスです。

私がユニットを台無しにしたかどうか誰かが教えてくれるように働いています:

  • 砂粒の体積0.00947mm ^ 3(Guardian
  • UUID4には122のランダムビットがあります-> 5.3e36の可能な値(Wikipedia
  • その多くの砂粒の体積= 5.0191e34 mm ^ 3または5.0191e + 25m ^ 3
  • その体積の立方ボックスの側面の長さ= 3.69E8mまたは369,000km
  • 木星の直径:139,820km(google)

実際、これは100%のパッキングを想定しているので、多分そのための係数を追加する必要があります!
負け
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.