既存の回答のいくつかは近いですが、次のいずれかがあるため、回答を投稿します。
- 総当たり攻撃が容易になるか、同じエントロピーに対してパスワードを長くする必要があるため、希望よりも小さい文字スペース
- RNG暗号学的に安全とみなされていません
- いくつかのサードパーティライブラリの要件であり、自分で実行するために何が必要かを示すのは興味深いかもしれないと思いました
count/strlen
生成されたパスワードのセキュリティ、少なくともIMHOは、あなたがそこに到達する方法を超えているため、この回答は問題を回避します。また、PHPを5.3.0以上と想定します。
問題を構成要素に分解してみましょう。
- 安全な乱数発生源を使用してランダムデータを取得する
- そのデータを使用して、印刷可能な文字列として表現する
最初の部分では、PHP> 5.3.0が関数を提供しますopenssl_random_pseudo_bytes
。ほとんどのシステムは暗号的に強力なアルゴリズムを使用していますが、ラッパーを使用するために確認する必要があることに注意してください。
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
2番目の部分base64_encode
では、バイト文字列を受け取り、元の質問で指定されたものに非常に近いアルファベットを持つ一連の文字を生成するため、これを使用します。私たちが持っ気にしなかった場合+
、/
および=
文字が、最終的な文字列で表示され、我々は、少なくとも結果たい$n
長い文字を、我々は単に使用できます。
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
この3/4
要因は、base64エンコーディングの結果、バイト文字列より少なくとも3分の1長い文字列が生成されるためです。$n
それ以外の場合は、結果は4の倍数で最大3文字長くなります。余分な文字は主にパディング文字=
であるため、何らかの理由でパスワードが正確な長さであるという制約があった場合は、必要な長さに切り詰めることができます。これは特に、特定のについて$n
、すべてのパスワードが同じ数で終わるため、結果のパスワードにアクセスできる攻撃者は、推測する文字が最大2文字少なくなるためです。
追加のクレジットとして、OPの質問のように正確な仕様を満たしたい場合は、もう少し作業を行う必要があります。ここでは、基本的な変換アプローチを省略し、すばやく簡単な方法を使用します。62エントリの長いアルファベットのため、どちらも結果で使用されるよりも多くのランダム性を生成する必要があります。
結果の余分な文字については、結果の文字列からそれらを単に破棄できます。バイト文字列が8バイトで始まる場合、base64文字の最大約25%がこれらの「望ましくない」文字になるため、これらの文字を単に破棄すると、OPが必要とするよりも短い文字列になります。次に、単純に切り捨てて、正確な長さにします。
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
より長いパスワードを生成する場合=
、PRNGに使用されるエントロピープールの排出が懸念される場合は、パディング文字が中間結果に占める割合がますます小さくなるため、より無駄のないアプローチを実装できます。