PHP で rand 関数を使用するスクリプトがあります。今、私はそれらの結果を本当に簡単に予測できるいくつかの怪談を読みました. これはクライアント側から可能ですか?
たとえば、 があるとしrand(0,10)
ます。次の数字を予測することは可能ですか?
rand()
関数は疑似乱数を返します。next
これは、数を予測できるという意味ではありません。ただし、この画像は単語の概念を説明できますpseudorandom
画像はrand
、Windows システムの機能を備えた単純なループから生成されます。
header("Content-type: image/png");
$im = imagecreatetruecolor(512, 512) or die("Cannot Initialize new GD image stream");
$white = imagecolorallocate($im, 255, 255, 255);
for ($y = 0; $y < 512; $y++) {
for ($x = 0; $x < 512; $x++) {
if (rand(0, 1)) {
imagesetpixel($im, $x, $y, $white);
}
}
}
imagepng($im); imagedestroy($im);
そんなにランダムじゃないですよね?でも、これでわかったら次の数字は予想できる?
真の乱数ジェネレーター (TRNG) と疑似乱数ジェネレーター (PRNG) の違いは、TRNG は予測不可能な物理的手段 (大気ノイズなど) を使用して数値を生成するのに対し、PRNG は数学的アルゴリズム (完全にコンピューター生成) を使用することです。
[...]
このような明白な視覚的パターンを生成する PRNG は多くありません。たまたま、言語 (PHP)、オペレーティング システム (Windows)、および関数 (rand()) の非常に悪い組み合わせです。
PRNGの状態をブルートフォースする必要があります。http://crypto.di.uoa.gr/CRYPTO.SEC/Randomness_Attacks_files/paper.pdf
PHP の rand() は、基礎となる標準ライブラリの実装を使用します。これは、オペレーティング システムによって異なります。
最初のステップとして、オペレーティング システムを定義します。
次のステップでは、Rand() 関数のソース コードとそれをシードするコードを取得します。
簡単にするために、PRNG のシードがサーバーのミリ秒時間のようなものであると仮定します。したがって、HTTP 要求が着信すると、PHP は PRNG をシードし、rand(0,10) を実行します。あなたがそうなるだろうと予測したい場合は...
クライアントの時計をサーバーの時計に同期させ、HTTP リクエストをサーバーに送信してからの正確な時間を統計的に導き出し、タイムスタンプ付きの応答 HTTP ヘッダーを読み取ります。
クライアント PRNG (サーバーと同じ実装) に、サーバーから rand(0,10) を要求する予測される将来の時刻をシードします。クライアントで rand(0,10) を実行し、正確な将来の時刻にリクエストをサーバーに送信すると、結果は同じになります。
Ping 時間、処理時間などにより、これはかなり強引なアプローチになります。
実際、インターネット経由 (サーバーに直接アクセスできない) では、PHP の rand() 関数の結果を予測することはあまりできません。
によって返される値は、疑似ランダム値rand()
のみです。
これは、マシンにアクセスできれば数値を計算できる可能性があることを意味しますが、実際にはそうはなりません。PHP の出力を見るだけでマシンにアクセスできないエンドユーザーには、次の値を計算したり予測したりするオプションはありません。PHPスクリプトの 1 回の実行内での複数のrand()
呼び出しの出力は*技術的に *予測可能ですが、これをそのまま使用することはできません。なぜなら、ユーザーは 1 回の全体実行の出力しか見ることができず、 PHPスクリプトの実行中に対話する機会がないからです。 .
これは、PHP のシードを生成するために使用される手順ですrand()
。
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (time(0) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
PHP の時点で4.2.0
、 The random number generator is seeded automatically.
ランドマニュアルから:
min (または 0) と max (または getrandmax() を含む) の間の疑似ランダム値。
したがって、ランダムはランダムではなく、疑似ランダムです。計算がどのように行われるかを知っていて、初期値を知っていれば、次の値を予測 (計算) できます。
真のランダム値が必要な場合は、別のアルゴリズムが必要です。たとえば、ホワイト ノイズに基づいています。
セキュアとセキュアを十分に区別したい場合があると思います。予測に関するあなたの質問に対する答えは「はい」です。疑似乱数ジェネレーターから生成された数値を予測することは可能です。しかし、より重要な問題は、これがどの程度発生する可能性があるかということだと思います。予測から何を守ろうとしていますか? 大規模なオンライン ゲーム Web サイトを運営している場合は、小規模な MUD サーバーを運営している場合よりも、真のランダム性を確保することがおそらくより重要です。ユーザーがパターンを破った場合の結果はより深刻であり、ユーザーが時間をかけてアルゴリズムを攻撃する動機を持つ可能性が高くなるため、これはより重要です。
Random.org のサービスも参照してください。彼らは、サーバーから真の乱数を取得できる API を提供します。それらは大気ノイズからエントロピーを取得しますが、これは少なくともユーザーに関する限り予測できないはずです。
これらの怪談を信用しないでください。Web アプリケーションの場合、予測は不可能であり、クライアント側から次の番号を決定することはできません。
なんで?
乱数ジェネレーターはすべてのリクエストの前にシードされ、クライアントはシード値を見ることができないためです! 予測は、すべての数値が同じリクエストで生成された場合にのみ機能します。