本「PHPのセキュリティ」(パート5)。 ランダム値のエントロピーの欠如







「PHPのセキュリティ」という本(パート1)

「PHPのセキュリティ」という本(パート2)

「PHPのセキュリティ」という本(パート3)

「PHPのセキュリティ」という本(パート4)







PHPのランダムな値はどこにでもあります。 すべてのフレームワーク、多くのライブラリ。 あなたはおそらく、トークンとソルトを生成するために、また関数への入力としてランダムな値を使用する一連のコードを書いたでしょう。 また、ランダムな値は、さまざまな問題の解決に重要な役割を果たします。







  1. プールまたは既知のオプションの範囲からオプションをランダムに選択します。
  2. 暗号化の初期化ベクトルを生成します。
  3. 許可時に予測不能なトークンまたは1回限りの値を生成するため。
  4. セッションIDなどの一意の識別子を生成するため。


これらすべての場合に、特徴的な脆弱性があります。 攻撃者が乱数ジェネレーター(RNG、乱数ジェネレーター)または疑似乱数ジェネレーター(PRNG、擬似乱数ジェネレーター)の出力を推測または予測する場合、攻撃者は、トークン、ソルト、ワンタイム値、および暗号化初期化ベクトルを使用して作成できますこのジェネレータ。 したがって、高品質のランダム値、つまり予測が非常に困難なランダム値を生成することは非常に重要です。 いかなる場合でも、パスワードリセットトークン、CSRFトークン、APIキー、ワンタイム値、認証トークンの予測可能性を許可しないでください!







PHPでは、さらに2つの潜在的な脆弱性がランダムな値に関連付けられています。







  1. 情報開示
  2. エントロピーの不足(不十分なエントロピー)。


これに関連して、「情報の開示」とは、擬似乱数ジェネレータの内部状態の漏洩、つまりその初期値(シード値)を指します。 このようなリークは、将来のPRNG出力の予測を大幅に促進できます。







「エントロピーの欠如」は、PRNGまたはその出力の初期内部状態(シード)の変動性が非常に小さいため、可能な値の範囲全体が比較的簡単にブルートフォースでソートされる状況を表します。 PHPプログラマにとってはあまり良いニュースではありません。







攻撃シナリオの例を使用して、両方の脆弱性を詳細に調べます。 しかし、最初に、PHPでのプログラミングに関して実際にランダムな値が何であるかを理解しましょう。







ランダム値は何をしますか?



ランダム変数の目的に関する混乱は、一般的な誤解によって悪化しています。 暗号的に永続的なランダム値と「他の用途」のあいまいな「一意の」意味との違いを聞いたことは間違いありません。 主な印象は、暗号化で使用されるランダムな値には高品質のランダム性(または、むしろ高いエントロピー)が必要であり、他のアプリケーションの値ではエントロピーが少なくて済むということです。 この印象は間違っており、逆効果です。 予測不可能なランダム値と些細なタスクに必要な値との本当の違いは、後者の予測可能性が有害な結果を伴わないことだけです。 これは通常、暗号化を問題の考慮から除外します。 言い換えれば、自明でないタスクでランダムな値を使用する場合、より強力なRNGを自動的に選択する必要があります。







ランダム値の強度は、それらを生成するために費やされるエントロピーによって決まります。 エントロピーは、「ビット」で表される不確実性の尺度です。 たとえば、バイナリビットを使用する場合、その値は0または1になります。攻撃者が正確な値を知らない場合、2ビットのエントロピー(つまり、コインを投げる)があります。 攻撃者が値が常に1であることを知っている場合、予測可能性は不確実性の反義語であるため、0ビットのエントロピーがあります。 また、ビット数は0〜2の範囲になります。たとえば、99%のバイナリビットが1の場合、エントロピーは0をわずかに超える可能性があります。







PHPでは、これをより明確に見ることができます。 mt_rand()



関数はランダムな値を生成します;これらは常に数字です。 文字、特殊文字、またはその他の意味は生成しません。 これは、攻撃者がバイトごとに当て推量がはるかに少ないこと、つまりエントロピーが低いことを意味します。 Linuxのsource /dev/random



からバイトを読み取ることでmt_rand()



を置き換えると、実際にランダムなバイトが得られます。システムデバイスドライバーやその他のソースによって生成されたノイズに基づいて生成されます。 明らかに、このオプションはエントロピーのビットを大幅に増やすため、はるかに優れています。







mt_rand()



の望ましくないことは、このジェネレーターが真の乱数ではなく、擬似乱数、または決定論的ランダムビットジェネレーター(決定論的ランダムビットジェネレーター、DRBG)とも呼ばれるという事実によっても示されます。 Mersenne Twisterと呼ばれるアルゴリズムを実装します。このアルゴリズムは、結果が真の乱数ジェネレーターの結果に近くなるように分散された数値を生成します。 mt_rand()



は、1つのランダム値のみを使用します。初期値(シード)に基づいて、固定アルゴリズムは擬似ランダム値を生成します。







この例を見てください、あなたはそれを自分でテストすることができます:







 mt_srand(1361152757.2); for ($i=1; $i < 25; $i++) { echo mt_rand(), PHP_EOL; }
      
      





これは、Mersenne vortex PHP関数が事前定義済みの初期値を受け取った後に実行される単純なループです。 これは、 mt_srand()



ドキュメントで例として引用されている関数の出力で取得され、現在の秒とマイクロ秒を使用しています。 上記のコードを実行すると、25個の擬似乱数が表示されます。 ランダムに見えますが、偶然ではなく、すべてが正常です。 コードを再度実行します。 何か気づいたことがありますか? つまり、同じ番号が表示されます。 3回目、4回目、5回目を実行します。 PHPの古いバージョンでは、結果が異なる場合がありますが、これは問題の場合には当てはまりません。これは、PHPのすべての最新バージョンで一般的なためです。







攻撃者がこのようなPRNGの初期値を受け取ると、 mt_rand()



すべての出力を予測できます。 したがって、初期値の保護は最重要事項です。 紛失すると、ランダムな値を生成する権利がなくなります...







次の2つの方法のいずれかで初期値を生成できます。









2番目のオプションが望ましいですが、今日のレガシーアプリケーションは、最新バージョンのPHPに移植した後でも、多くの場合mt_srand()



使用を継承します。







これにより、攻撃者が初期値(シード回復攻撃攻撃)を復元するリスクが高まり、将来の値を予測するのに十分な情報が得られます。 その結果、このようなリーク後のアプリケーションは、情報漏えい攻撃に対して脆弱になります。 これは、明らかに受動的な性質にもかかわらず、本当の脆弱性です。 ローカルシステムに関する情報を漏らすことは、その後の攻撃で攻撃者を助けることができ、これは多層防御の原則に違反します。







PHPのランダム値



PHPは3つのPRNGを使用します。攻撃者がアルゴリズムで使用される初期値にアクセスすると、攻撃の結果を予測できます。







  1. 線形合同ジェネレーター(LCG)、 lcg_value()



  2. メルセンヌ・ワールウィンド、 mt_rand()



  3. ローカルでサポートされているrand()



    C関数。


また、これらのジェネレーターは、 array_rand()



uniqid()



などの関数の内部ニーズに使用されます。 これは、攻撃者が必要なすべての初期値を取得した場合、PHP言語の内部PRNGを使用して、これらおよび他の機能の出力を予測できることを意味します。 これは、ジェネレーターへの多数の呼び出しの助けを借りて攻撃者を混乱させることによって保護を改善することができないことも意味します。 これは、特にオープンソースアプリケーションに当てはまります。 攻撃者は、既知の初期値のすべての出力データを予測できます。







非自明なタスクに対して生成されるランダム値の品質を向上させるために、PHPはオペレーティングシステムによって提供される外部エントロピーのソースを必要とします。 Linuxは通常/dev/urandom



を使用しopenssl_pseudo_random_bytes()



mcrypt_create_iv()



またはmcrypt_create_iv()



関数を使用して、直接読み取るか、間接的にアクセスできます。 どちらもWindowsで暗号学的に安全な擬似乱数ジェネレーター(CSPRNG)を使用できますが、PHPでは、これらの関数によって提供される拡張機能なしにこのジェネレーターからデータを受信するためのユーザー空間に直接的な方法はありません。 つまり、サーバーバージョンのPHPでOpenSSLまたはMcrypt拡張機能が有効になっていることを確認してください。







/dev/urandom



はPRNGですが、多くの場合、非常にエントロピーの高いソース/dev/random



から新しい初期値を取得します。 これにより、攻撃者にとっては面白くないターゲットになります。 ブロッキングリソースであるため、 /dev/random



から直接読み取らないようにします。 彼がエントロピーを使い果たすと、システム環境から再び十分なエントロピーが得られるまで、すべての測定値がブロックされます。 最も重要なタスクには、 /dev/random



使用する必要があります。







これはすべて私たちをルールに導きます:







  ,     ,   openssl_pseudo_random_bytes().           /dev/urandom.           ,                  .
      
      





このルールの基本的な実装は、SecurityMultiToolリファレンスライブラリにあります。 いつものように、PHP内部では、PHPコアに安全なソリューションを直接含めるのではなく、プログラマの生活を複雑にすることを好みます。







十分な理論で、上記で武装したアプリケーションを攻撃する方法を見てみましょう。







PHPの乱数ジェネレーターへの攻撃



いくつかの理由により、PHPはPRNGを使用して重要なタスクを解決します。







openssl_pseudo_random_bytes()



関数はPHP 5.3でのみ利用可能でした。 Windowsでは、バージョン5.3.4がリリースされるまでロックの問題が発生していました。 また、PHP 5.3では、Windowsのmcrypt_create_iv()



関数がMCRYPT_DEV_URANDOMソースのサポートを開始しました。 これ以前は、WindowsではMCRYPT_RANDのみがサポートされていました。実際、内部のニーズのためにrand()



使用するのと同じシステムPRNGです。 ご覧のとおり、PHP 5.3の登場以前は多くのギャップがあったため、以前のバージョンで作成された多くのレガシーアプリケーションは、より強力なPRNGに切り替えられなかった可能性があります。







OpensslおよびMcrypt拡張の選択はユーザー次第です。 PHP 5.3を搭載したサーバーでも可用性に依存できないため、アプリケーションは、多くの場合、PHPに組み込まれたPRNGを非自明なランダム値を生成するためのフォールバックとして使用します。







ただし、どちらの場合も、低エントロピーの初期値を持つPRNGを使用して生成されたランダムな値を適用する重要なタスクがあります。 これにより、初期回復攻撃に対して脆弱になります。 簡単な例を見てみましょう。







次のコードを使用してアプリケーション全体のさまざまなタスクで使用されるトークンを生成するアプリケーションをオンラインで見つけたと想像してください。







 $token = hash('sha512', mt_rand());
      
      





トークンを生成するより複雑な手段がありますが、これは良いオプションです。 ここでは、SHA512でハッシュ化mt_rand()



呼び出しが1つだけmt_rand()



ます。 実際には、プログラマーがPHPのランダム値関数が「かなりランダム」であると判断した場合、おそらく「暗号化」という言葉が聞こえるまで単純化されたアプローチを選択するでしょう。 たとえば、暗号化されていない場合には、アクセストークン、CSRFトークン、ワンタイムAPI値、およびパスワードリセットトークンが含まれます。 続行する前に、このアプリケーションの脆弱性の詳細を説明します。これにより、一般にアプリケーションが脆弱になる原因をよりよく理解できます。







脆弱なアプリケーションの特性



これは完全なリストではありません。 実際には、機能のリストは異なる場合があります!







1. サーバーはmod_phpを使用します。 これにより、KeepAliveを使用すると、同じPHPプロセスで複数のリクエストを処理できます。



PHPの乱数ジェネレーターはプロセスごとに初期値を受け取るため、これは重要です。 プロセスに対して2つ以上の要求を行うことができる場合、同じ初期値を使用します。 攻撃の本質は、1つのトークンの開示を適用して、SAME初期値に基づいて生成された別のトークンを予測するために必要な初期値を抽出することです(つまり、同じプロセスで)。 mod_phpは複数のクエリを使用して関連するランダムな値を取得するのに理想的であるため、1つのクエリでmt_rand()



関連する複数の値を抽出できる場合があります。 これにより、mod_phpの要件が冗長になります。 たとえば、 mt_rand()



初期値の生成に使用されるエントロピーの一部は、同じクエリのセッションIDまたは出力値を介してリークする可能性があります。







2.サーバーは、mt_rand()トークンに基づいて生成されたCSRFトークン、パスワードリセットトークン、またはアカウント確認トークンを表示します。



初期値を抽出するには、PHPのジェネレーターによって生成された数値を直接確認する必要があります。 そして、それがどのように使用されるかは関係ありません。 mt_rand()



出力、ハッシュ化されたCSRF、アカウント確認トークンなど、利用可能な任意の値から抽出できます。 ランダムな値が出力での異なる動作を決定する間接的なソースでさえも適切であり、これによりこの値が明らかになります。 主な制限は、予測しようとしている2番目のトークンを生成するのと同じプロセスからのものでなければならないということです。 これが「情報漏えい」の脆弱性です。 すぐにわかるように、PRNGの出力漏れは非常に危険です。 脆弱性は単一のアプリケーションに限定されないことに注意してください:両方が同じPHPプロセスを使用する場合、サーバー上の1つのアプリケーションでPRNG出力を読み取り、それを使用して同じサーバー上の別のアプリケーションの出力を決定できます。







3.既知の弱いトークン生成アルゴリズム



あなたはそれを計算することができます:









一部のトークン生成方法はより明白であり、一部はより一般的です。 本当に弱い生成ツールは、PHP乱数ジェネレーターの1つ(たとえばmt_rand()



)、弱いエントロピー(未定義データの他のソースはありません)、および/または弱いハッシュ(たとえばMD5またはハッシュなし)の使用によって区別されます。 上記のコード例には、弱い生成メソッドの兆候があります。 また、SHA512ハッシュを使用して、マスキングが常に不十分なソリューションであることを示しました。 SHA512は弱いハッシュです。SHA512は迅速に計算されるため、攻撃者はあらゆるCPUまたはGPUで入力データを非常に高速でブルートフォースできます。 また、ムーアの法則も有効であることを忘れないでください。つまり、ブルートフォースの速度は、CPU / GPUの新世代ごとに増加することを意味します。 したがって、パスワードは、プロセッサのパフォーマンスやムーアの法則に関係なく、クラッキング結果に固定時間が必要なツールを使用してハッシュ化する必要があります。







攻撃



攻撃は非常に簡単です。 PHPプロセスへの接続の一環として、クイックセッションを実行し、2つの個別のHTTPリクエスト(リクエストAとリクエストB)を送信します。 セッションは、2番目の要求が受信されるまでサーバーによって保持されます。 リクエストAの目的は、CSRF、パスワードリセットトークン(メールで攻撃者に送信)などの利用可能なトークンを取得することです。 任意のIDのリクエストなどで使用されるインラインマークアップなど、他の機能についても忘れないでください。初期値が得られるまで、元のトークンを苦しめます。 これはすべて、初期値を復元する攻撃の一部です。初期値のエントロピーが非常に小さいため、ブルートフォースまたは事前に計算されたレインボーテーブルを検索できます







リクエストBは、より興味深い問題を解決します。 ローカル管理者のパスワードをリセットするリクエストを作成しましょう。 これにより、トークンの生成が開始されます(両方の要求が同じPHPプロセスに正常に送信された場合、要求Aを使用して引き出した同じ初期値に基づく乱数を使用します)。 このトークンは、管理者がメールで送信されたパスワードリセットリンクを使用する瞬間を見越して、データベースに保存されます。 リクエストAからトークンの初期値を抽出できる場合、リクエストBからトークンがどのように生成されるかを知って、パスワードリセットトークンを予測します。 そのため、管理者が手紙を読む前にリセットリンクをたどることができます!







イベントのシーケンスは次のとおりです。







  1. クエリAを使用して、トークンを取得し、リバースエンジニアリングして初期値を計算します。
  2. クエリBを使用して、同じ初期値に基づいて生成されたトークンを取得します。 このトークンは、将来のパスワードリセットのためにアプリケーションデータベースに保存されます。
  3. SHA512ハッシュを解読して、サーバーが生成した乱数を取得します。
  4. 受信したブルートフォースランダム値を使用して、それを使用して生成された初期値。
  5. 初期値を使用して一連のランダムな値を計算しますが、これはおそらくパスワードリセットトークンの根底にある可能性があります。
  6. このトークンを使用して、管理者パスワードをリセットします。
  7. 管理者アカウントにアクセスして、楽しんで利益を得ます。 まあ、少なくとも楽しんでください。


ハッキングしましょう...







ハッキングアプリケーションハック



ステップ1.リクエストAを実行してトークンを抽出します



ターゲットトークンとパスワードリセットトークンはmt_rand()



出力に依存すると想定しています。 したがって、それを選択する必要があります。 想像上のシナリオのアプリケーションでは、すべてのトークンは同じ方法で生成されるため、CSRFトークンを単純に抽出し、将来のために保存できます。







手順2.要求Bを実行して、管理者アカウント用に生成されたパスワードリセットトークンを取得します



このリクエストは、パスワードリセットフォームの簡単な送信です。 トークンはデータベースに保存され、メールでユーザーに送信されます。 このトークンを正しく計算する必要があります。 サーバーの特性が正確な場合、クエリBはクエリAと同じPHPプロセスを使用します。したがって、どちらの場合も、 mt_rand()



呼び出しは同じ初期値を使用します。 クエリAを使用して、リセットフォームのCSRFトークンをキャプチャし、手順を効率化するための送信を有効にすることもできます(中間ラウンドトリップを除く)。







ステップ3.要求Aで受信したトークンのSHA512ハッシュをハックする



SHA512はプログラマにa敬の念を抱かせます。SHA -2アルゴリズムファミリ全体で最大の数を持っています 。 ただし、被害者が選択したトークン生成方法には1つの問題があります-ランダムな値は数字によってのみ制限されます(つまり、不確実性またはエントロピーの程度は無視できます)。 mt_getrandmax()



出力を確認すると、 mt_rand()



が生成できる最大の乱数は2 mt_rand()



億であり、些細なことです。 この限られた数の機能により、SHA512はブルートフォースに対して脆弱になります。







ただ私の言葉を受け入れないでください。 最新世代のディスクリートグラフィックカードをお持ちの場合は、次の方法をお試しください。 単一のハッシュを探しているので、ブルートフォース用の素晴らしいツール-hashcat-liteを使用することにしました。 これはhashcatの最速バージョンの1つであり、Windowsを含むすべての主要なオペレーティングシステムで使用できます。







このコードを使用してトークンを生成します。







 $rand = mt_rand(); echo "Random Number: ", $rand, PHP_EOL; $token = hash('sha512', $rand); echo "Token: ", $token, PHP_EOL;
      
      





このコードは、リクエストAからトークンを再現し(必要な乱数が含まれており、SHA512ハッシュに隠されています)、hashcatを実行します。







 ./oclHashcat-lite64 -m1700 --pw-min=1 --pw-max=10 -1?d -o ./seed.txt <SHA512 Hash> ?d?d?d?d?d?d?d?d?d?d
      
      





これらすべてのオプションの意味は次のとおりです。









すべてが正常に機能し、GPUが溶けない場合、Hashcatは数分でハッシュ化された乱数を計算します。 はい、分。 前に、エントロピーの仕組みについて説明しました。 自分で見てください。 mt_rand()



関数の機能mt_rand()



非常に少ないため、すべての値のSHA512ハッシュを実際に非常に短時間で計算できます。 したがって、 mt_rand()



出力をハッシュすることは無意味mt_rand()









ステップ4.新たにクラックされた乱数を使用して初期値を復元する



上で見たように、SHA512から生成されたmt_rand()



値を抽出するのに数分かかります。 ランダムな値で武装して、ブルートフォース用の別のツールphp_mt_seedを実行できます。 この小さなユーティリティはmt_rand()



出力をmt_rand()



し、ブルートフォースが初期値を計算した後、それに基づいて分析された値を生成できます。 現在のバージョンをダウンロードし、コンパイルして実行します。 コンパイルで問題が発生した場合は、古いバージョンを試してください(新しい仮想環境で問題が発生しました)。







 ./php_mt_seed <RANDOM NUMBER>
      
      





CPUで実行されるため、SHA512をハッキングするよりも少し時間がかかる場合があります。 適切なプロセッサでは、ユーティリティは数分で初期値の可能な範囲全体を見つけます。 — (. . , ). : , PHP . , , , .







, , . mt_rand()



, , (, mt_rand()



). , , . , mt_rand()



Python.







5.



, mt_rand()



. , :







 function predict($seed) { /** *   PRNG   */ mt_srand($seed); /** *       */ mt_rand(); /** *         */ $token = hash('sha512', mt_rand()); return $token; }
      
      





.







6 7. !



URL, , . , , HTML ( ). XSS- , « » (Man-In-The-Browser). , ? , , , , . — , , .









mt_rand()



. , mt_rand()



, , « ».







, . , , mt_rand()



- , , , «» , . , . mt_rand()



— , ?







. mt_rand()



( ) . , mt_rand()



. — , mt_rand()



, .







. , , , , .









, PRNG, PHP, (. . ). :







 $token = hash('sha512', uniqid(mt_rand()));
      
      





. , PHP- uniqid()



. :







-.







, — . - , mt_rand()



, mt_rand()



- . uniqid()



— . . . .







, «», . . . 1 000 000 . 1 , (, HTTP Date ), . , uniqid()



-:







 gettimeofday((struct timeval *) &tv, (struct timezone *) NULL); sec = (int) tv.tv_sec; usec = (int) (tv.tv_usec % 0x100000); /* usec     0xF423F,     * usecs    . */ if (more_entropy) { spprintf(&uniqid, 0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg(TSRMLS_C) * 10); } else { spprintf(&uniqid, 0, "%s%08x%05x", prefix, sec, usec); } RETURN_STRING(uniqid, 0);
      
      





, PHP:







 function unique_id($prefix = '', $more_entropy = false) { list($usec, $sec) = explode(' ', microtime()); $usec *= 1000000; if(true === $more_entropy) { return sprintf('%s%08x%05x%.8F', $prefix, $sec, $usec, lcg_value()*10); } else { return sprintf('%s%08x%05x', $prefix, $sec, $usec); } }
      
      





, uniqid()



13 . 8 — Unix ( ), . 5 — . , uniqid()



, uniqid()



:







 $id = uniqid(); $time = str_split($id, 8); $sec = hexdec('0x' . $time[0]); $usec = hexdec('0x' . $time[1]); echo 'Seconds: ', $sec, PHP_EOL, 'Microseconds: ', $usec, PHP_EOL;
      
      





-. , :







 echo uniqid(), PHP_EOL; // 514ee7f81c4b8 echo uniqid('prefix-'), PHP_EOL; // prefix-514ee7f81c746 echo uniqid('prefix-', true), PHP_EOL; // prefix-514ee7f81c8993.39593322
      
      







, , uniqid()



— . , uniqid()



. , , 1 000 000 . , . uniqid()



:







 $token = hash('sha512', uniqid(mt_rand()));
      
      





, , mt_rand()



uniqid()



, SHA512-, . uniqid()



, , HTTP Date. . , !







 <?phpphp echo PHP_EOL; /** *        */ mt_srand(1361723136.7); $token = hash('sha512', uniqid(mt_rand())); /** *      , *  ,      HTTP Date    *  mt_rand()       ;) */ $httpDateSeconds = time(); $bruteForcedSeed = 1361723136.7; mt_srand($bruteForcedSeed); $prefix = mt_rand(); /** *  HTTP Date   ,    *    (second tick)   uniqid()  time(). */ for ($j=$httpDateSeconds; $j < $httpDateSeconds+2; $j++) { for ($i=0; $i < 1000000; $i++) { /** Replicate uniqid() token generator in PHP */ $guess = hash('sha512', sprintf('%s%8x%5x', $prefix, $j, $i)); if ($token == $guess) { echo PHP_EOL, 'Actual Token: ', $token, PHP_EOL, 'Forced Token: ', $guess, PHP_EOL; exit(0); } if (($i % 20000) == 0) { echo '~'; } } }
      
      





?



, uniqid() TRUE:







 $token = hash('sha512', uniqid(mt_rand(), true));
      
      





-, php_combined_lcg()



. lcg_value()



, PHP- uniqid()



. , , , . , . mt_rand()



, PHP- .







 static void lcg_seed(TSRMLS_D) /* {{{ */ { struct timeval tv; if (gettimeofday(&tv, NULL) == 0) { LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11); } else { LCG(s1) = 1; } #ifdef ZTS LCG(s2) = (long) tsrm_thread_id(); #else LCG(s2) = (long) getpid(); #endif /* Add entropy to s2 by calling gettimeofday() again */ if (gettimeofday(&tv, NULL) == 0) { LCG(s2) ^= (tv.tv_usec<<11); } LCG(seeded) = 1; }
      
      





- , . .







gettimeofday()



Unix Epoch ( ). , , microsecond()



, . ID , Linux 32 768. , 4 , /proc/sys/kernel/pid_max



, .







, , LCG, . , mt_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 . . , , : , ( 0 + - gettimeofday())



. gettimeofday()



, ( PHP ). , mt_rand()



, .







php_combined_lcg()



. lcg_value()



, PHP-. , . — , .







...



, . , php_combined_lcg()



, — , . lcg_value()



, mt_rand()



, PRNG, PHP. lcg_value()



, . LCG ( mt_srand()



, , - -). , : PHP.







 spprintf(&buf, 0, "%.15s%ld%ld%0.8F", remote_addr ? remote_addr : "", tv.tv_sec, (long int)tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
      
      





(pre-hash) ID , IP, , … php_combined_lcg()



. ( 1 ID 2 php_combined_lcg()



, ), . , .







, , , PHP session.entropy_file session.entropy_length. ID , ( ) php_combined_lcg()



LCG-. PHP 5.3 , , , . , ID LCG.







Windows- , LCG-.







, LCG , mt_rand()



, mt_rand()



.







uniqid()



?







 $token = hash('sha512', uniqid(mt_rand(), true));
      
      





. ( !). ID , ID.







, ? uniqid()



, LCG, . , ID , , , ( !).









PHP . API PRNG- , . openssl mcrypt. , , , .







, , , . , mt_rand()



, , . , , RandomLib . .







. , . . : , ; , . — .







RandomLib , . , mt_rand()



, uniqid()



lcg_value()



, PID, , - , $_ENV, posix_times() . . , RandomLib. , - (. . , - hash()



).







 /** *  32-  .     : * — generateInt()      PHP_INT_MAX * — generateString()        */ $factory = new \RandomLib\Factory; $generator = $factory->getMediumStrengthGenerator(); $token = hash('sha512', $generator->generate(32));
      
      





, OpenSSL Mcrypt (footprint) RandomLib RandomLib , PRNG- SecurityMultiToo l.








All Articles