単純な自動インクリメントの主キーを使用する代わりに、APIを通じて公開するランダムな識別子を生成するのが一般的です。理由はたくさんあります:
これらのIDを生成するときに、より単純なもの(crypto.randomBytes()
など)を使用するよりも、暗号的に安全な疑似乱数ジェネレータ(Node.jsのMath.random()
のように)を使用することに大きなメリットがありますか?
Math.random()
は通常、現在の時刻からシードされます。したがって、毎日ほぼ同じ時刻に生成されるオブジェクトで衝突が発生する可能性があります。
セキュリティの観点からは、これはこれらの「ランダムな」値が攻撃者によって予測可能であることを意味します。
何か他のものでシードされていても、暗号的に安全でない疑似乱数ジェネレーターは、十分な値がキャプチャされた場合にその状態を明らかにできます。これが、セキュリティの観点から、暗号で保護された疑似乱数ジェネレーター(例:crypto.randomBytes()
)によって生成された値のみを使用する方が良い理由です。
[〜#〜] csprng [〜#〜] sには、セキュリティでの使用に適した特定のプロパティがあります。
- すべてのCSPRNGは、次のビットテストを満たす必要があります。つまり、ランダムシーケンスの最初のkビットが与えられると、50%よりも高い成功確率で(k + 1)番目のビットを予測できる多項式時間アルゴリズムはありません。 Andrew Yaoは、1982年に、次のビットのテストに合格したジェネレーターが、ランダム性に関する他のすべての多項式時間統計テストに合格することを証明しました。
- すべてのCSPRNGは「状態侵害拡張」に耐える必要があります。その状態の一部またはすべてが明らかになった(または正しく推測された)場合、啓示の前に乱数のストリームを再構築することは不可能であるべきです。さらに、実行中にエントロピー入力がある場合、入力の状態に関する知識を使用して、CSPRNG状態の将来の状態を予測することは不可能です。
このようなジェネレーターを使用すると、セキュリティ要件が満たされます。
ただし、これらが適切なアクセス制御(認証と承認)で最初のケースを保護することから予測できないという事実を許してはなりません。 URLは秘密と見なされるべきではなく、URLがリークする可能性がある多くの方法があります(隠しカメラでのショルダーサーフィン、HTTPリファラーヘッダーのリーク、プロキシおよびブラウザーログ)。また、URLがわかっていて、それを保護するために予測できないシークレットに依存している場合、そのURLにアクセスするユーザーは常にアクセスでき、これを取り消すことはできません。覚えておいてください-彼らは簡単にブックマークすることができます。
予測不可能な値を使用すると、アプリケーションに必要であると見なされた場合に、他の要件が間違いなく役立ちます。予測可能性と衝突を防ぐのに十分なエントロピーを超える128ビットのランダム値を使用することをお勧めします。
はい。あなたがリストしたすべてのことを達成するためには、暗号的に安全なRNGが必要です。
Math.randomがどのように機能するかはわかりませんが、2ビットでシードされているが128ビットの数値を生成する2bitRNGと呼ぶTERRIBLE RNGを考えてみてください。 2bitRNGに2ビットのエントロピーをシードし、それを使って10,000個の乱数を生成します。
2ビットしかシードしていないので、可能なシードは4つだけです。したがって、攻撃者は、40,000の可能な乱数のスペースを検索するだけで、正しいシードと現在のシーケンスの位置を見つけることができます。これは小さな数字であり、控えめなコンピュータを使用すると、ほんの一瞬で計算できます。攻撃者がこれを知ると、次のシーケンスと、生成したRNGの数がわかります。
Math.randomがどれほどひどいのか、他のどのような攻撃に対して脆弱であるのかはわかりませんが、安全ではないため、セキュリティの目的で使用しないことをお勧めします。適切な安全なRNGは、大量のエントロピー(約128ビット以上)を使用して、先ほど説明した種類の攻撃を防ぎ、予測可能な結果を生成しません。
tl; dr:可能であれば、CSPRNGを使用します。
多くの場合、CSPRNGからではない(バインドされている)UUIDが使用されますが、(CS以外の)-PRNGが定期的に再シードされない場合(長生きするサーバープロセスの場合など)は、これは良いアイデアではない可能性があります。
そのような識別子の作成に使用するアルゴリズムが既知であり、その入力が少数のサンプルで推定できる場合(CのRand()
の場合など)、質問で列挙したすべてのプロパティが失われます。
したがって、予測可能なPRNGを使用して単一のシードから値を生成することは悪いことですが、悪いPRNGが使用前に適切なエントロピーで再シードされると、ほとんどのWebシナリオでは通常のケース)、それで問題ありません。
したがって、可能であれば、CSPRNGを使用してください。できない場合は、各生成ステップの前に、エントロピーを高くして再シードしてください。
これはすべて、生成プロセスのシード方法と使用方法によって異なります。
実行時間の長いプロセスがある場合は、CSPRNGを使用してください。短期間のプロセスを使用している場合は、適切なエントロピーソースと基本的には任意のPRNGを使用してください。
データが何であれ、可能な限り暗号化された安全な乱数ジェネレータを使用することをお勧めします。良い面と悪い面を上回っています。
また、このコードが後でどのように使用されるかはわかりません。コードレビューを行う場合、ほとんどの場合、暗号化されていない安全な乱数ジェネレータの使用に常にフラグを立てます。
また、セッションごとの使用 間接オブジェクト参照 の使用を確認することもできます。クライアントからデータを操作したり、クライアントからデータを返したりする前に、承認/特権チェックを実行することを忘れないでください。
前に戻って、別の視点から問題を見てみましょう。連番を使用した場合に起こり得る最悪の事態は何ですか?列挙について述べましたが、列挙による脅威は何ですか? #00015と#00016を発行し、ID#00017が次に生成される可能性があると予測した場合、誰かが問題を引き起こす可能性はありますか?おそらく誰かが、今後のIDに関連付けられる可能性のある電子メールまたはTwitterアカウントをハイジャックする可能性があります。
そして、誰かがID#00023がID#42234より古いと判断できる場合、問題は何ですか?古いIDは通常、新しいIDよりも多くのリソースを利用できますか? ID#00123が5月1日に発行され、ID#00256が6月1日に発行されたことを私は知っています。有名な有名人が5月に登録したと発表したことを知った場合、IDを推測するための番号は133しかありません。誰かのID番号を推測すると問題が発生するのですか、それともとにかく公開情報になるのですか?
この時点で、連続したID番号を本当に秘密にしておく必要があるのか、それとも公開できるのかを理解する必要があります。
次に、脅威ベクトル(これらが現実的な脅威である場合)を確認し、リスクを考え出します。これらのほとんどは、クライアントのシークレットIDが公開された場合のリスクであり、システムへの脅威ではありません。しかし、クライアントを保護していなければ、あなたの評判は確かに破壊され、あなたの冒険は失敗します。これらが有効な脅威である場合、真剣に受け止める必要があります。
次に、Pseudo-Random Number Generator(PRNG)が1つの特定の目的のために作成されたという理解を追加します:統計の問題をモデル化するための統計的によく分散された数値の生成。これらは、「使用できない」数値を生成するために作成されたことはありません。ほとんどのPRNGは、シーケンシャルナンバジェネレータであることから離れた数学の問題にすぎません。推測可能な数を生成する機能を減らすために、多くのシードフープをジャンプしてみることもできますが、それはまさに暗号的に安全なPRNG(CSPRNG)が解決するように設計されている問題です。CSPRNGは、推測不可能なものを生成するように特別に設計されています番号。
いくつかのリスクをよく理解したところで、これらの脅威からクライアントを保護する必要がある(または必要ない)理由を理解する必要があります。 PRNGとCSPRNGの違いをよりよく理解することで、確実な決定を下すことができます。
これらの秘密を保持する必要がある場合は、CSPRNGを使用してクライアントを保護する必要があります。それらを秘密にしておく必要がない場合は、連番を使用し、乱数ジェネレータを完全に排除することでシステムの複雑さを軽減する必要があります。
暗号的に保護されていないPRNGは、シーケンスを生成するパラメーターを決定する可能性のある分析に対して脆弱です。シーケンスがわかったら、次の値だけでなく、使用中のシーケンス番号の総数も決定できます。現実の世界でこれを行う魅力的な例については、 https://en.wikipedia.org/wiki/German_tank_problem を参照してください。
連続した識別子を推測できないようにするだけでなく、通常は同じコンテキスト内で同じ識別子を2回生成することも避けたいです。 PRNG=を使用する場合、識別子の数はPNRGの期間によって制限され、シード生成の弱点に対して脆弱です。暗号で保護された乱数ジェネレータを使用する場合、識別子の数識別子のサイズによって制限され、シードの問題に対して脆弱ではないはずです。
数が最大で数千の識別子が生成されるクローズドシステムで使用される場合、PRNGはおそらくOKです。
識別子を分散して生成し、グローバルに一意にする必要がある場合、暗号化された安全な乱数ジェネレータを使用すると、衝突がないことを確認できます。