JPCERT コーディネーションセンター

MSC02-J. 高品質の乱数を生成する

擬似乱数発生器(PRNG)は決定論的数学的アルゴリズムを使い、統計的に良質な特性を持つ数列を生成する。しかし、生成される数列は完全な乱数ではない。PRNG は通常、数学的なシード(seed)に基づいて乱数の生成を開始する。アルゴリズムはこのシードを使って出力する値と新しいシードを生成し、次にそのシードを用いて次の値を生成するという具合である。

Javaの標準API java.util.Random クラスは PRNG の機能を提供する。この PRNG は可搬性があり、かつ再現性がある。したがって、同一のシードを使って生成された java.util.Random クラスの2つのインスタンスは、すべてのJava実行環境においてまったく同じ数列を生成する。シードは、アプリケーションの初期化やシステムの再起動の度に再利用されることが多い。システム時計から取得した現在時刻をシードにする場合もある。攻撃者は攻撃対象となる脆弱なシステムを調べることで、シードにどのような値が使用されたかを知り、今後使用されるシードの値を予測する表を作成することができる。

ゆえに、システムのセキュリティ確保やセンシティブなデータの保護のために java.util.Random クラスを使用してはならない。java.security.SecureRandom クラス等、より安全な乱数発生器を使用すること。

違反コード

以下の違反コード例はセキュアではない java.util.Random クラスを使用している。このクラスは同一のシードに対してまったく同一の数列を生成するため、生成される数列は予測可能である。

import java.util.Random;
// ...

Random number = new Random(123L);
//...
for (int i = 0; i < 20; i++) {
  // [0, 20] の範囲の乱数を生成
  int n = number.nextInt(21);
  System.out.println(n);
}
適合コード

以下の適合コードでは java.security.SecureRandom クラスを使用し、より品質の高い乱数を生成している。

import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
// ...

public static void main (String args[]) {
   try {
     SecureRandom number = SecureRandom.getInstance("SHA1PRNG");
     // [0, 20] の範囲の乱数を生成
     for (int i = 0; i < 20; i++) {
       System.out.println(number.nextInt(21));
     }
   } catch (NoSuchAlgorithmException nsae) { 
     // 例外ハンドラへ
   }
}
例外

MSC02-EX0: java.util.Random クラスのデフォルトコンストラクタを使用すると、「このコンストラクタの他の呼出しと区別可能な値」をシードとして使用するため、セキュリティをいくぶん改善する[API 2006]。この場合もやはり、その使用はセンシティブではないデータを処理するアプリケーションのみに限るべきである。Javaのデフォルトでは、シードはミリ秒で表されるシステム時間である。このコンストラクタを使用する場合は、この例外に該当する旨を明示しなくてはならない。

import java.util.Random;
// ...

Random number = new Random(); // デモのみに使用
int n;
//...
for (int i = 0; i < 20; i++) {
  // シードを新しくする
  number = new Random();
  // 新たに [0, 20] の範囲の乱数を作る
  n = number.nextInt(21);
  System.out.println(n);
}

ゲームにランダムな動作を追加したり単体テストを行うような、セキュリティが重要でない場合であれば、Random クラスを使用しても構わない。しかし、重要なので繰返すが、暗号アプリケーションなどセキュリティがより重要な意味を持つアプリケーションで Random クラスが生成するエントロピーの低い乱数を使用するのは不適切である。

MSC02-EX1: 予測可能な擬似乱数が必要となる場合もある。たとえばプログラムのリグレッションテストを行う場合など。そのような場合は、セキュアではない java.util.Random クラスを使用しても構わない。しかし、セキュリティ関連のアプリケーションにおいてこの例外を適用してもよいのは、アプリケーションのテストを行う場合のみであり、実運用環境に使用してはならない。

リスク評価

予測可能な乱数列は、暗号アプリケーションなどのような重要なシステムのセキュリティを損なう恐れがある。

ルール 深刻度 可能性 修正コスト 優先度 レベル
MSC02-J P12 L1
関連する脆弱性

CVE-2006-6969

関連ガイドライン
CERT C Secure Coding Standard MSC30-C. Do not use the rand() function for generating pseudorandom numbers
CERT C++ Secure Coding Standard MSC30-CPP. Do not use the rand() function for generating pseudorandom numbers
MITRE CWE CWE-327. Use of a broken or risky cryptographic algorithm
  CWE-330. Use of insufficiently random values
  CWE-332. Insufficient entropy in PRNG
  CWE-336. Same seed in PRNG
  CWE-337. Predictable seed in PRNG
参考文献
[API 2006]  Class Random
[API 2006] Class SecureRandom
[FindBugs 2008] BC. Random objects created and used only once
[Monsch 2006]  
翻訳元

これは以下のページを翻訳したものです。

MSC02-J. Generate strong random numbers (revision 92)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter