web-dev-qa-db-ja.com

UUIDの衝突

特にバージョン4(ランダム)UUIDを使用して、UUIDの衝突の可能性について実際の調査を行った人はいますか? UUIDを生成しますか?

私の同僚は、UUIDの衝突のテストは時間の浪費であると考えていますが、データベースからの重複するキーの例外をキャッチし、新しいUUIDで再試行するコードを常に入れています。しかし、UUIDが別のプロセスからのものであり、実際のオブジェクトを参照している場合、問題は解決されません。

33
Paul Tomblin

ウィキペディアにはいくつかの詳細があります:

http://en.wikipedia.org/wiki/Universally_unique_identifier

http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates

しかし、確率は、ビットが完全にランダムである場合にのみ保持されます。ただし、他の回答でリンクされているRFC http://tools.ietf.org/html/rfc4122#page-14 は、バージョン4でこれを定義しています。

「4.4。[...]バージョン4のUUIDは、真の乱数または疑似乱数からUUIDを生成するためのものです。[...]他のすべてのビットをランダム(または疑似ランダム)に選択した値に設定します。」

これにより、xkcdランダムジェネレータ http://xkcd.com/221/ から、量子ノイズを使用するハードウェアデバイスまで、ほとんど何でも可能になります。 RFCのセキュリティに関する考慮事項:

「6.さまざまなホストでUUIDを生成する分散アプリケーションは、すべてのホストで乱数ソースに依存する必要があります。これが不可能な場合は、ネームスペースバリアントを使用する必要があります。」

私はこれを次のように読みます。あなたはあなた自身のアプリケーション内であなたのランダムジェネレーターに責任がありますが、これと他のものは信頼に基づいています。選択したランダムジェネレーターを正しく理解して使用する自分の能力を信頼できない場合は、衝突をチェックすることをお勧めします。他のプロセスのプログラマーを信頼していない場合は、衝突を確認するか、別のバージョンのUUIDを使用してください。

18
Secure

衝突が発生した場合は必ず検出し、発生した場合はアプリケーションで例外をスローする必要があります。例えば。 UUIDがデータベースの主キーとして使用されている場合、衝突するIDを挿入すると、データベースはエラーをスローするはずです。

ただし、衝突が発生した場合に新しいUUIDを生成するコードを記述し、再び時間を無駄にしようとすると思います。衝突が発生する可能性は非常に小さいため、例外をスローすることは、それに対処するための完全に合理的な方法です。

覚えておいてください、それはあなた自身のコードを書く時間の無駄であるだけでなく、コードをより複雑にし、次の人が読むのをより困難にし、ほとんど何の利益もありません。

11
Pete

これは非常に良い質問です。どこでもUUIDを使用することがラッシュで十分に考慮されているとは思いません。確かな研究は見つかりませんでした。

提案:ここを非常に注意深く読み、暗号化についてよく理解してください。 128ビットUUIDを使用する場合、「誕生日効果」は、約2 ^ 64のキーを生成した後に衝突が発生する可能性があることを示しています各キーに128ビットのエントロピーがある場合

これが事実であることを確認することは実際にはかなり困難です。真のランダム性は、(a)放射性崩壊(b)ランダムなバックグラウンドラジオノイズから生成される可能性があり、注意しない限りしばしば汚染されます。逆バイアスされたツェナーダイオードから取得。 (私は最後で遊んだことがあり、それは魅力のように動作します、ところで)。

ユーザーが2 ^ 64(つまり、約10 ^ 19)に近いキーを生成し、それらすべてを相互にチェックしていない限り、「1年の使用でこれを見たことがない」などの発音は信用しません。ささいな運動。

問題はこれです。鍵を他のすべての人が共通の鍵空間で生成している他のすべての鍵と比較すると、100ビットのエントロピーしかないとしましょう。約2 ^ 50で衝突が発生し始めます。約10 ^ 15キー。データベースに1千億のキーのみを入力した場合、衝突が発生する可能性はまだ無視できます。チェックしないと、ペタローサイズのデータ​​ベースに侵入する予期しないエラーが後で発生します。これはかみつくかもしれません。

このようなUUIDを生成するためのアプローチが複数あるという事実自体が、一時的なけいれんを引き起こす可能性があります。タイプ4のUUIDに十分なエントロピーを備えた「真にランダムな」プロセスを使用しているジェネレーターがほとんどないことに気づいた場合、過度に懸念する必要がありますnlessジェネレーターのエントロピーコンテンツを注意深く調べました。 (ほとんどの人はこれを行わないでしょう、またはその方法さえ知っています。DieHarderスイートから始めるかもしれません)。擬似乱数生成と真の乱数生成を混同しないでください。

入力したエントロピーは自分が持っているエントロピーであり、暗号化関数を適用してキーを混乱させるだけではエントロピーが変化しないことを理解することが重要です。スペース全体が数字の0と1で構成されている場合、エントロピーの内容が次の2つの文字列と同じであることは直感的にわかりにくいかもしれません。 !@@#&^%$$),. m} "と"完全に異なるものを今すぐに "まだ2つのオプションがあります。

ランダム性は正しく理解するのが難しいので、「専門家がそれを見たので大丈夫だ」と単純に信じるだけでは不十分かもしれません。エキスパートの暗号技術者(実際に熟練している人はほとんどいません)が、間違いを犯したことを認める最初の人です。ハートブリード、DigiNotarなどを信頼しました。

Paul Tomblinは適切な注意を払っていると思います。私の2c。

7
user199506

あなたが持っている問題は、「乱数ジェネレーター」を使用していて、そのジェネレーターがどれほどランダムであるかわからない場合、衝突の確率は実際には未知であるということです。乱数ジェネレータが何らかの方法で相関している場合、衝突の確率は劇的に増加する可能性があります。

衝突の確率が非常に小さい場合でも、根本的な問題があります。確率は0ではありません。これは、衝突が最終的に発生することを意味しますが、衝突はそれほど頻繁には発生しません。

頻繁にUUIDを生成して使用するほど、衝突が発生する可能性が高くなります。 (1年に1を生成することは、1秒あたり100万を生成するよりも長い待機時間を意味します。

その確率が有限で不明であり、多くのUUIDを使用している場合は、衝突の結果を考慮する必要があります。例外をスローしてビジネスアプリケーションをシャットダウンすることが許容できない場合は、実行しないでください。 (頭の上の例:「ライブラリチェックインの更新中にWebサーバーをシャットダウンしても問題ありません...頻繁に発生することはありません」および「給与計算システムを途中でシャットダウンしても問題ありません。これらの決定はキャリアを制限する動きかもしれません。)

ただし、アプリケーションによっては、さらに悪い場合もあります。 UUIDの存在をテスト(つまり、ルックアップを行う)していない場合は、新しいUUIDを作成します(これは、十分に一般的なことです)。レコードをリンクしている、または関係を作成している場合があります。 、実際には、フックすべきではないUUIDを介して2つのものをフックしている場合。これは、例外をスローしても何も解決されず、どこかで検出できない混乱が発生するものです。これは、情報漏えいの原因となり、非常に恥ずかしいことです。 (例:銀行にログインすると、誰か他​​の人の口座の残高を確認できます!悪い!)

概要:UUIDの使用方法と衝突の結果を考慮する必要があります。これにより、衝突を検出して回避するか、衝突が発生した場合に単純なアクションを実行するか、何もしないかを決定します。単純で単一の万能のソリューションは、状況によっては不適切である可能性があります。

6
quickly_now

関連する2つの問題があります。

  1. 使用される乱数ジェネレーターの品質。

  2. 生成される可能性のあるUUIDの量。

「ランダム」UU​​IDには、122個のランダムビットがあります。完全なランダム性を仮定すると、約2 ^ 61の生成されたUUID(2 ^ 122の平方根)で最初の衝突が予想されます。この地球上のすべての人が1秒あたりのUUIDを生成する場合、これは10,000,000,000 * 365 * 24 * 60 * 60 = 315360000000000000 UUIDであり、これは2 ^ 58に非常に近い値です。つまり、数年後に最初の衝突が発生します。アプリケーションがこれらの数値に近い場所を取得しない限り、ランダムジェネレーターの品質が適切であれば、衝突が発生しないことを確信できます。

乱数ジェネレーターについて:標準Cライブラリジェネレーター(直接、間接、または類似のジェネレーター)を使用している場合は、おそらくそれらに時間をシードしているため、使いにくいです。これらは、衝突を回避するのに十分なエントロピーを利用できません。ただし、Linuxを使用している場合は、/dev/urandomから16バイトのデータを読み取るだけです。これにより、実際のランダムイベントにアクセスできるカーネルによって攪拌されているエントロピープールが使用されます。通常、UUIDを実際に、起動シーケンスの初期に生成しない限り、/dev/urandomは真のランダムソースのように動作するはずです。