次の値を推測する機能は、rand
何srand
が呼び出されたかを判断できることに関係しています。特に、事前に決められた数でシードするsrand
と、予測可能な出力が得られます!PHPインタラクティブプロンプトから:
[charles@charles-workstation ~]$ php -a
Interactive shell
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php >
これは単なる吸虫ではありません。ほとんどのPHPのバージョン*ほとんどのプラットフォームで**シーケンス97を生成します、97、39、77、93時にsrand
「1024年とD。
明らかに、これはPHPの問題ではなく、これrand
自体の実装の問題です。同じ問題は、Perlを含む同じ(または類似の)実装を使用する他の言語で発生します。
その秘trickは、PHPの健全なバージョンはすべてsrand
「不明」な値を事前にシードすることです。ああ、それは本当に未知ではありません。からext/standard/php_rand.h
:
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
したがって、time()
PID、およびphp_combined_lcg
で定義されたでの数学ext/standard/lcg.c
です。私はここでc&pするつもりはありません。まあ、私の目が眩しくなり、狩りをやめることにしました。
することを示しているグーグルでのビットPHPの他の領域は、最高のランダム生成特性を有していない、との通話をするためにphp_combined_lcg
ここに目立つが、分析の特にこのビット:
この関数(gettimeofday
)は、銀の大皿に正確なサーバータイムスタンプを返すだけでなく、「PHPから」「より多くのエントロピー」を要求すると、LCG出力を追加しuniqid
ます。
うんいますuniqid
。の値は、2番目の引数を真の値に設定してphp_combined_lcg
呼び出した後、結果の16進数を見ると見えるようuniqid
です。
さて、私たちはどこにいましたか?
そうそう。 srand
。
そのため、ランダムな値を予測しようとしているコードがを呼び出さないsrand
場合、によって提供される値を決定する必要がphp_combined_lcg
ありますuniqid
。その値が手元にあれば、残りの値をブルートフォースすることが可能です- time()
、PIDおよびいくつかの数学。リンクされたセキュリティの問題はセッションの切断に関するものですが、同じテクニックがここでも機能します。繰り返しますが、記事から:
上記の攻撃手順の概要は次のとおりです。
- サーバーが再起動するのを待ちます
- uniqid値を取得します
- これからRNGシードをブルートフォース
- オンライン状態をポーリングして、ターゲットが表示されるのを待ちます
- 現在のサーバー時間とRNG値を追跡するために、ステータスポーリングとuniqidポーリングをインターリーブします
- ポーリングで確立された時間とRNG値の間隔を使用したサーバーに対するブルートフォースセッションID
必要に応じて、最後の手順を置き換えるだけです。
(このセキュリティの問題は、現在のバージョン(5.3.6)よりも以前のPHPバージョン(5.3.2)で報告されたため、動作が変更されuniqid
たりphp_combined_lcg
変更されたりする可能性があるため、この特定の手法は機能しなくなる可能性があります。 YMMV。)
一方、製品を作成しようとしているコードがsrand
手動で呼び出した場合、の結果よりも何倍も優れたものを使用していない限り、php_combined_lcg
おそらく値を推測してローカルにシードするのがはるかに簡単になります正しい番号のジェネレータ。srand
また、手動で呼び出すほとんどの人は、これがいかにひどいアイデアであるかを認識しないため、より良い値を使用する可能性は低いでしょう。
mt_rand
同じ問題に悩まされていることは注目に値します。mt_srand
既知の値でシードすると、予測可能な結果が生成されます。エントロピーを基にすることopenssl_random_pseudo_bytes
は、おそらくより安全な賭けです。
tl; dr:最良の結果を得るには、PHP乱数ジェネレーターをシードしないでください。また、善のために、uniqid
ユーザーに公開しないでください。これらのいずれかまたは両方を実行すると、乱数がより推測しやすくなります。
PHP 7の更新:
PHP 7.0はrandom_bytes
、random_int
コア機能として導入します。それらは、基盤となるシステムのCSPRNG実装を使用し、シードされた乱数ジェネレーターが持つ問題から解放します。これらは実質的にに似ていますopenssl_random_pseudo_bytes
が、拡張機能をインストールする必要はありません。 PHP5ではポリフィルを使用できます。
*:Suhosinのセキュリティパッチは、のふるまい変更rand
し、mt_rand
すべての呼び出しで、そのような彼らは常にことを再シードを。スホシンはサードパーティから提供されます。一部のLinuxディストリビューションでは、公式のPHPパッケージにデフォルトで含まれていますが、他のディストリビューションではオプションになっていますが、他のディストリビューションでは完全に無視されています。
**:プラットフォームおよび使用されている基礎となるライブラリ呼び出しに応じて、ここに記載されているものとは異なるシーケンスが生成されますが、Suhosinパッチを使用しない限り、結果は再現可能です。