12

数日間の研究と議論の後、訪問者からエントロピーを収集するこの方法を思いつきました (私の研究の歴史はここで見ることができます)

ユーザーが訪問すると、次のコードを実行します。

$entropy=sha1(microtime().$pepper.$_SERVER['REMOTE_ADDR'].$_SERVER['REMOTE_PORT'].
$_SERVER['HTTP_USER_AGENT'].serialize($_POST).serialize($_GET).serialize($_COOKIE)); 

注: ペッパーは、手動で設定されたサイト/セットアップごとのランダムな文字列です。

次に、次の (My)SQL クエリを実行します。

$query="update `crypto` set `value`=sha1(concat(`value`, '$entropy')) where name='entropy'";

つまり、訪問者のリクエストのエントロピーを他の人が既に収集したエントロピーと結合します。

それで全部です。

次に、乱数を生成する場合は、収集したエントロピーを出力と組み合わせます。

$query="select `value` from `crypto` where `name`='entropy'";
//...
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF).$entropy.microtime())))); 

注: 最後の行は、phpseclib の crypt_rand 関数の修正版の一部です

エントロピー収集/乱数生成に関するスキームやその他のアイデア/情報についてのあなたの意見を教えてください.

ps: /dev/urandom のような乱数ソースについては知っています。このシステムは単なる補助システム、または (これらのソースにアクセスできない場合) フォールバック スキームです。

4

8 に答える 8

11

最良のシナリオでは、最大の危険はローカル ユーザーによる情報漏えいの悪用です。最悪のシナリオでは、全世界があなたのデータを予測できます。あなたと同じリソース (同じログ ファイル、同じネットワーク デバイス、同じボーダー ゲートウェイ、またはあなたとリモート接続の間を走る同じ回線) にアクセスできるすべてのユーザーは、乱数を巻き戻してトラフィックを盗聴できます。発生器。

彼らはどのようにそれをしますか?もちろん、情報理論の基本的な応用と暗号知識も必要です。

しかし、あなたは間違った考えを持っていません!PRNG にランダム性の実際のソースをシードすることは、通常、上記の攻撃の発生を防ぐのに非常に役立ちます。たとえば、この同じレベルの攻撃は、システムのエントロピーが低い場合、またはランダム性のソースが再現可能である場合、システムごとにデータがどのように入力されるかを理解している誰かによって悪用される可能性があります。/dev/random

エントロピーのプールをシードするプロセスを十分に保護できる場合 (たとえば、安全な回線を介して複数のソースからデータを収集することによって)、誰かが傍受できる可能性は、望ましい結果に近づくにつれてますます小さくなります。ワンタイム パッドの暗号品質。

言い換えれば、単一のメルセンヌ ツイスターに供給されるランダム性の単一のソースを使用して、PHP でこれを実行しないでください。に代わるシステム固有の最良の代替手段から読み取り、/dev/random「真の」ランダム性のできるだけ多くの安全で明確なソースからエントロピープールをシードすることにより、適切に実行してください。これらのランダム性のソースにアクセスできないとあなたが述べたことは理解していますが、同様の機能がすべての主要なオペレーティングシステムに提供されている場合、この概念は奇妙です. したがって、この文脈における「補助システム」の概念は疑わしいと思います。

これは、エントロピーのソースを認識しているローカル ユーザーによる攻撃に対して依然として脆弱ですが、マシンを保護し、内部の真のエントロピーを増加/dev/randomさせることで、侵入者を除いて汚い仕事を行うことははるかに困難になります。・ミドルアタック

実際にアクセス可能な場合について/dev/randomは、かなり簡単にシードできます。

あなたのアプリケーションを保護するために頑張ってください。


PS:今後、Security.SECryptography.SEでこのような質問をしてみてください。

于 2012-03-31T23:31:09.410 に答える
4

Random.Org を使用する

本当に乱数が必要な場合は、random.orgを使用してください。これらの数値は、大気ノイズによって生成されます。PHP のライブラリに加えて、単純なリクエストで真の乱数を取得できるhttp インターフェースも備えています。

https://www.random.org/integers/?num=10&min=1&max=6&col=1&base=10&format=plain&rnd=new

これは、サーバー上で追加の PECL 拡張機能を使用せずに、PHP で実際の乱数を簡単に取得できることを意味します。

他のユーザーがあなたの乱数を「盗む」ことができたくない場合 (MrGomez が主張しているように)、証明書チェックで https を使用してください。以下は、https 証明書チェックの例です。

$url = "https://www.random.org/integers/?num=10&min=1&max=6&col=1&base=10&format=plain&rnd=new";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$response = curl_exec($ch);
if ($response === FALSE)
        echo "http request failed: " . curl_error($ch);
else
        echo $response;    
curl_close($ch);

https リクエストの作成方法に関する詳細情報が必要な場合:

セキュリティの詳細

繰り返しになりますが、攻撃者があなたと同時に random.org にクエリを実行すると、同じ数値を取得して予測する可能性があると主張する人もいるかもしれません. random.org がこのように機能するかどうかはわかりませんが、本当に懸念がある場合は、ダミーのリクエストを投げて攻撃者をだますか、取得した乱数の特定の部分のみを使用することで、チャンスを減らすことができます。

MrGomez がコメントで述べているように、これはセキュリティに対する究極の解決策ではなく、エントロピーの可能性のあるソースの 1 つとしてのみ考慮されるべきです。

パフォーマンス

もちろん、ブリッツ レイテンシが必要な場合は、1 つのクライアント リクエストごとに 1 つの random.org リクエストを実行するのは最善の考えではないかもしれませんが、5 分ごとのように、乱数を事前にキャッシュするために1 つの大きなリクエストを実行するだけではどうでしょうか?

于 2012-04-02T21:00:41.730 に答える
1

要するに、私が知る限り、PHP スクリプト内でエントロフィを生成する方法はありません。この非回答で申し訳ありません。phppassのような十分に確立されたスクリプトを見ても、それらのフォールバック システムが何らかの魔法を実行できないことがわかります。

問題は、とにかく試してみるべきかどうかです。システムを GPL の下で公開したいので、それがどのようなシナリオで使用されるかはおそらくわかりません。私の意見では、ランダムなソースを要求するか、すぐに失敗する(適切なエラー メッセージで終了する) のが最善の方法です。そのため、システムを使用したい開発者は、問題があることをすぐに知ることができます。

ランダムソースから読み取るには、関数を呼び出すことができますmcrypt_create_iv()...

$randomBinaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);

...この関数は、オペレーティング システムのランダム プールから読み取ります。PHP 5.3 以降では、Windows サーバーでも同様に実行されるため、ランダム ソースの処理は PHP に任せることができます。

于 2012-04-07T13:17:39.090 に答える
0

アップデート2コードレビュー全員への警告:元の質問のコードは使用しないでください。それはセキュリティ上の責任です。このコードがどこでもオンラインになっている場合システム、ネットワーク、データベース全体を悪意のあるユーザーに公開するため、コードを削除します。コードだけでなく、すべてのユーザーデータを公開します。

ユーザー入力をシリアル化しないでください。コードですでに実行している場合は、サーバーを停止してコードを変更します。これは、自分で暗号化を行わないことの素晴らしい例です。

更新1 :実際のセキュリティのためには、エントロピーに推測 できないランダム性が必要です。エントロピーを追加するための適切なオプションには、質問の参照先があります。これは、 microtime()自体ではなく、スクリプトの実行時間の デルタを使用することです。Deltaはサーバーの負荷に依存しているためです。また、ハードウェア環境、温度、ネットワーク負荷、電力負荷、ディスクアクセス、CPU使用率、および電圧変動の組み合わせも予測できません。

Time()、タイムスタンプ、またはマイクロタイムを使用することは、実装の欠陥です。

スクリプト実行DeltaExempleコードは次のとおりです。

@martinstoeckliは、暗号化に適したランダム生成は

 mcrypt_create_iv($lengthinbytes, MCRYPT_DEV_URANDOM);

しかし、暗号モジュールを持っていないという要件の範囲外です

SQLでは、生成された番号と組み合わせて RAND()を使用します。http://www.tutorialspoint.com/mysql/mysql-rand-function.htm

PHPオファーと Rand()関数

http://php.net/manual/en/function.rand.php

彼らはあなたに同じ番号を与えないので、あなたは両方を使うことができます。

于 2012-04-07T15:42:07.810 に答える
0

前に言ったように、私の rand 関数は phpseclib の crypt_random 関数の修正版です。私の最初の投稿で与えられたリンクでそれを見ることができました。少なくとも phpseclib 暗号化ライブラリの作成者はそれを確認しました。通常のアプリでは不十分ですか?私は極端な/理論的なセキュリティについて話すのではなく、実際に必要な程度の実用的なセキュリティについて話します.同時に、Web上のほとんどすべての通常のアプリケーションで「簡単に」/「十分に低コストで」利用できます.

phpseclib の crypt_random は、最悪の場合 (openssl_random_pseudo_bytes または urandom が利用できない) には効果的かつ静かに mt_rand (これは本当に弱いことを知っておく必要があります) にフォールバックしますが、私の関数はそのような場合にはるかに安全なスキームを使用します。これは、ブルート フォーシング/その出力の予測がはるかに困難であり、実際にはすべての通常のアプリ/サイトで十分であるというスキームへのフォールバックにすぎません。時間の経過とともに収集される可能性のある(実際には非常に可能性が高く、予測/回避が難しい)余分なエントロピーを使用しますが、これは部外者にとってすぐに知ることがほとんど不可能になります。この可能なエントロピーを mt_rand の出力 (および他のソースの出力: urandom、openssl_random_pseudo_bytes、mcrypt_create_iv) に追加します。知っておくべきことが通知された場合、このエントロピーは加算できますが、減算することはできません。(ほぼ確実に非常にまれな)最悪の場合、その余分なエントロピーは0または非常に小さい量になります。ほとんどすべてのケースであると私が思う平凡なケースでは、それは実際には必要以上のものになると思います。(私は膨大な暗号学の研究を行ってきたので、私が考えると言うとき、それは通常のプログラマーよりもはるかに情報に基づいた科学的分析に基づいています)。

変更した crypt_random の完全なコードを参照してください。

function crypt_random($min = 0, $max = 0x7FFFFFFF)
{
    if ($min == $max) {
        return $min;
    }

    global $entropy;

    if (function_exists('openssl_random_pseudo_bytes')) {
        // openssl_random_pseudo_bytes() is slow on windows per the following:
        // http://stackoverflow.com/questions/1940168/openssl-random-pseudo-bytes-is-slow-php
        if ((PHP_OS & "\xDF\xDF\xDF") !== 'WIN') { // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
            extract(unpack('Nrandom', pack('H*', sha1(openssl_random_pseudo_bytes(4).$entropy.microtime()))));
            return abs($random) % ($max - $min) + $min; 
        }
    }

    // see http://en.wikipedia.org/wiki//dev/random
    static $urandom = true;
    if ($urandom === true) {
        // Warning's will be output unles the error suppression operator is used.  Errors such as
        // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
        $urandom = @fopen('/dev/urandom', 'rb');
    }
    if (!is_bool($urandom)) {
        extract(unpack('Nrandom', pack('H*', sha1(fread($urandom, 4).$entropy.microtime()))));
        // say $min = 0 and $max = 3.  if we didn't do abs() then we could have stuff like this:
        // -4 % 3 + 0 = -1, even though -1 < $min
        return abs($random) % ($max - $min) + $min;
    }


    if(function_exists('mcrypt_create_iv') and version_compare(PHP_VERSION, '5.3.0', '>=')) {
        @$tmp16=mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
        if($tmp16!==false) {
            extract(unpack('Nrandom', pack('H*', sha1($tmp16.$entropy.microtime()))));
            return abs($random) % ($max - $min) + $min;
        }
    }


    /* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
       Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:

       http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/

       The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:

       http://svn.php.net/viewvc/php/php-src/tags/php_5_3_2/ext/standard/php_rand.h?view=markup */
    static $seeded;
    if (!isset($seeded) and version_compare(PHP_VERSION, '5.2.5', '<=')) { 
        $seeded = true;
        mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
    }

    extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF).$entropy.microtime()))));
    return abs($random) % ($max - $min) + $min;

}

$entropy には、これまでに結合されたすべてのリクエスト パラメータのエントロピー + 現在のリクエストのパラメータ エントロピー + インストール時に手動で設定されたランダムな文字列 (*) のエントロピーから得られる余分なエントロピーが含まれます。

*: 長さ: 22、小文字と大文字 + 数字で構成 (128 ビット以上のエントロピー)

于 2012-04-10T17:26:22.023 に答える
-1

rand() ではなく rn_rand() を使用する必要があります

于 2014-01-27T10:11:36.187 に答える