web-dev-qa-db-ja.com

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

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

369
Jason

とても安全:

ある人が隕石にぶつかることの年間リスクは170億分の1の確率であると推定され、これは確率が約0.00000000006(6×10)であることを意味します。−11これは、1年に数十兆のUUIDを作成し、1つの複製を作成する可能性と同じです。つまり、今後100年間に毎秒10億のUUIDを生成した後で初めて、複製が1つだけ作成される確率は約50%になります。

警告:

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

出典:普遍的に一意な識別子に関するウィキペディアの記事の ランダムUUID確率の重複セクション (リンクは12月からの改訂につながります)編集前の2016年はセクションを作り直しました。

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

360
lutz

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

130
rein

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

  • バージョン1は、時間ベースのMACアドレスUUIDです。 128ビットには、ネットワークカードのMACアドレス(製造元によって一意に割り当てられている)用の48ビットと、100ナノ秒の分解能を持つ60ビットのクロックが含まれています。その時計 603年頃にラップ だからこれらのUUIDは少なくともそれまで安全である(あなたが毎秒1000万以上の新しいUUIDを必要とするか、誰かがあなたのネットワークカードをクローンするのでなければ)。時計は1582年10月15日に始まるので、私は「少なくとも」と言うので、時計が折り返されてから重複の可能性が少しでもあるまでに約400年があります。

  • バージョン4は乱数UUIDです。 6つの固定ビットがあり、残りのUUIDは122ビットのランダム性です。 Wikipedia または重複が非常にありそうもないことを説明する他の分析を参照してください。

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

  • バージョン2はバージョン1と似ていますが、クロックが小さいため、もっと早くラップアラウンドします。しかし、バージョン2のUUIDはDCE用なので、これらを使うべきではありません。

だから、すべての実用的な問題のために彼らは安全です。あなたがそれを確率に任せることに不快感を覚えるならば(例えば、あなたの一生の間に大きな小惑星によって地球が破壊されるのを心配している人のタイプです)、バージョン1 UUIDを使うことを確認あなたの人生の中で、あなたは3603 ADを超えて生きることを計画していない限り)。

では、なぜ誰もが単にバージョン1のUUIDを使用しないのですか?これは、バージョン1のUUIDによって、それが生成されたマシンのMACアドレスが明らかになり、予測可能になるためです。これら2つのことは、それらのUUIDを使用するアプリケーションにセキュリティ上の影響があります。

93
Hoylen

これに対する答えは、UUIDのバージョンによって大きく異なります。

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

UUIDを生成するために、期間の短い不適切にシードされたPRNGが使用される場合、私はそれがまったく安全ではないと言うでしょう。

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

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

私の場合、私が使っているPRNGはひねくれたひねりで、/ dev/urandomを含む複数のソースからのシード方法に注意しています。 Mersenne twisterの周期は2 ^ 19937 - 1です。繰り返しuuidが表示されるまでには、かなり長い時間がかかります。

16
Matt

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

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

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

14
Dave Vogt

UUIDスキームは一般に、擬似乱数要素だけでなく現在のシステム時間、そして利用可能であればネットワークMACアドレスのようなある種のしばしばユニークなハードウェアIDも使用します。

UUIDを使用することの全体的なポイントは、あなたが自分でできるよりもユニークなIDを提供するより良い仕事をするためにあなたがそれを信頼するということです。これはあなた自身のものを転がすのではなく、サードパーティの暗号化ライブラリを使うことの背後にある同じ理論的根拠です。自分でやるのはもっと楽しくなるかもしれませんが、そうすることは一般的に責任がありません。

8
Parappa

これがユニークなものをテストするためのテストスニペットです。 @ scalabl3のコメントにヒントを得た

面白いのは、偶然にも偶然の一致、運、そして神の介入のレベルで、まったく同じ2つを連続して生成することができるということです。 :Dはい、それは起こりません。複製を作成したときのその瞬間について考える楽しさを言っているだけ!スクリーンショットのビデオ! - scalabl3 '15年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 <[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/>
5
Tschallacka

何年もそれをやっています。決して問題にぶつかることはありません。

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

それが持っている唯一の欠点はあなたがいくつかの情報を素早く見つけるためにいくつかのクエリを書いているときあなたがキーのコピーとペーストをたくさんやっているときです。あなたはもう覚えやすい短いIDをもう持っていません。

5
Posthuma

私は他の答えに同意します。 UUIDはほとんどすべての実用的な目的に対して十分に安全です。1そしてもちろんあなたのためです。

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

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

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

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

  2. UUIDを生成し、これまでに発行したすべてのUUIDを記録する集中型または分散型サービスを構築します。新しいUUIDが生成されるたびに、UUIDが以前に発行されたことがないことを確認します。そのようなサービスは、サービスを実行している人々が絶対的に信頼できるものであり、壊れないものであると仮定した場合、技術的に簡単に実装できます(私は思います)。残念ながら、そうではありません...政府が干渉する可能性があるときは特にそうです。そのため、このアプローチはおそらく非実用的であり、3 現実の世界では不可能です。


1 - UUIDの一意性が、核ミサイルがあなたの国の首都で発射されたかどうかを決定するならば、あなたの仲間の市民の多くは「可能性は極めて低い」と確信しないでしょう。したがって、私の「ほぼすべて」の資格です。

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

3 - 誰かがこの問題に関する何らかの研究論文を知っているなら、コメントしてください。

3
Stephen C

これがあなたにとって重要かどうかはわかりませんが、 GUIDはグローバルに一意ですが、GUIDのサブストリングは一意ではありません

2
Grant Wagner