JavaScript では、ブラウザーで乱数を選択するための 2 つの一般的な方法、Math.random と crypto.getRandomValues を提供します。デモでは同じように見えますが、互換性はありません。 Math.random は、セキュリティ以外の作業を目的とした高速擬似乱数ジェネレータです。 crypto.getRandomValues は、シークレット、トークン、および攻撃者が予測できないものを対象とした、暗号的に安全な PRNG (CSPRNG) です。このガイドでは、Math.random が安全でない場合の違い、モジュロ バイアスが素朴なコードにどのように侵入するか、ブラウザで安全なランダムな整数と小数を生成する方法について説明します。
クイック回答
Math.random は、アニメーション、シャッフルされたプレイリスト、装飾的な UI、および予測可能性がセキュリティ リスクにならないゲームに使用します。パスワード、API キー、セッション トークン、抽選、一意のサンプル、および予測に抵抗する必要があるものには、crypto.getRandomValues を使用します。 ToolsMinify の 乱数ジェネレーター と パスワード ジェネレーター はどちらも Web 暗号を使用します。Math.random は使用しません。
Math.random が実際に行うこと
Math.random は、半開範囲 [0, 1) の浮動小数点数を返します。エンジンは、ランタイムによってシードされた決定論的アルゴリズムを使用してこれを実装します。紙吹雪の粒子、ランダムなテスト器具のラベル、または今日のヒントを選ぶなど、多様性だけが必要な場合には、高速で十分です。
秘密にするようには設計されていません。古い環境では、十分な出力からシードまたは内部状態を推測できました。最新のエンジンがシードを強化したとしても、Math.random は依然としてセキュリティの観点から間違った API です。プラットフォームが暗号強度を保証しておらず、多くのチュートリアルが偏った整数トリックでラップしているためです。
- 用途: UI アニメーション、ゲーム、シャッフル デモ、非機密サンプリング
- 悪いもの: パスワード、リセットトークン、宝くじ形式の抽選、暗号ナンス、API キー
- [0, 1) の浮動小数点を返します - 整数やセキュリティ API ではありません
crypto.getRandomValues の機能
crypto.getRandomValues は Web Crypto API の一部です。型付き配列 (Uint32Array など) を渡すと、ブラウザーはオペレーティング システムのエントロピー ソースからの暗号的に強力なランダム値をその配列に入力します。これは、ブラウザが TLS やその他のセキュリティ機能に使用するランダム性と同じクラスです。
値は予測が難しいため、サーバーに何も送信したくない場合にクライアントでシークレットを生成するのに適しています。そのため、プライバシーを第一に考えたパスワードと番号の生成ツールは Web Crypto を好み、完全にブラウザーで実行されます。
- Web Crypto 契約に基づく暗号的に安全な (CSPRNG)
- ページが読み込まれるとオフラインで動作します
- シークレットをアップロードしてはいけないクライアント側ツールに最適
モジュロバイアス - ランダムな整数におけるサイレントバグ
一般的なスニペットは value = randomUint32 % n です。 n が 32 ビット範囲全体を均等に分割しない場合、一部の余りが他のものよりも頻繁に現れます。この偏りは、2^32 に比べて巨大な n 範囲ではわずかですが、これは現実であり、ラッフル、サイコロ、または「勝者を選ぶ」ツールで使用される小さな範囲では、それを回避する必要があります。
修正: 拒否サンプリング
32 ビット値を描画します。 2^32 のスペースの上部にある不完全な残りの領域に落ちた場合は、捨てて再度描画します。その場合のみ、モジュロ n を取得します。 [0, n) 内のすべての整数は同様の可能性を持ちます。 ToolsMinify の安全なジェネレーターはこのパターンを使用します。
一意の乱数が必要な場合
セキュリティと公平性は別の仕事です。勝者を重複させてはいけないラッフルでは、最小値と最大値の範囲内で代替なしのサンプリング (独自の抽選) が必要です。パスワードには、文字セット全体での置換を伴う高いエントロピーが必要です。どちらも依然として暗号のランダム性から開始する必要があります。一意性だけでは Math.random が安全になるわけではありません。
包括的な整数範囲の場合、一意の値の数は (最大値 - 最小値 + 1) を超えることはできません。小数の場合、「一意」は通常、間違ったモデルです。個別に生成するか、整数に切り替えます。
ブラウザで安全な乱数を生成する
日常的に使用するために、拒否サンプリングを自分で実装する必要はありません。すでに Web 暗号化を使用しているクライアント側ジェネレーターを開き、範囲を設定して、結果をコピーします。
- 乱数ジェネレーター - 安全なランダムな整数または小数、一括リスト、オプションの一意の描画 - ブラウザーの crypto.getRandomValues。
- パスワードジェネレータ - 長さと文字セットを制御できる強力なランダム パスワード - 同じ Web 暗号化基盤。
- UUID ジェネレーター - 衝突すべきでない識別子の UUID v4 / v7、ULID、および NanoID。
実践的なチェックリスト
- 次の値を予測することで、誰かがアクセス、金銭、または不当な利益を得ることができるでしょうか?
- 「はい」の場合は、crypto.getRandomValues (またはその上に構築されたツール) を使用してください。Math.random は使用しないでください。
- ランダム ビットを範囲にマッピングする場合は、生のモジュロの代わりに拒否サンプリングを使用します。
- パスワードとトークンの場合は、大きな文字プールと十分な長さを持つ専用のジェネレーターを推奨します。
- シークレットがサーバー ログにヒットしないようにする場合は、クライアント側で生成を維持します。
よくある質問
Math.random は大丈夫ですか?
はい - セキュリティ以外のランダム性の場合。ビジュアルの多様性、リアルマネーを賭けないゲーム、デモ データは問題ありません。番号が秘密であるか、動機のある攻撃者に対して公平でなければならない瞬間に、Web 暗号化に切り替えます。
crypto.getRandomValues は遅いですか?
Math.random よりも遅いですが、パスワード、数千の宝くじ番号、またはテスト ID を生成する場合、ブラウザーでは違いは無関係です。ここでは、マイクロベンチマークよりも正確さと予測不可能性の方が重要です。
安全なジェネレーターにはサーバーが必要ですか?
いいえ。ブラウザはすでに CSPRNG を公開しています。クライアント側ツールはローカルで値を生成できるため、シークレットがデバイスから流出することはありません。これが ToolsMinify が使用するモデルです。
Node.js の crypto.randomInt はどうですか?
サーバーでは、Math.random の代わりにプラットフォーム暗号モジュール (crypto.randomInt など) を使用します。同じルールが適用されます。セキュリティに配慮したランダム性には CSPRNG API が必要です。
今すぐ安全な RNG を試してください
無料の 乱数ジェネレーター を使用して、ブラウザーで暗号化された安全な整数または小数を描画します。最小/最大、オプションの固有モードを設定してからコピーします。何もアップロードされていません。