web-dev-qa-db-ja.com

phpでランダムなパスワードを生成する

私はphpでランダムなパスワードを生成しようとしています。

しかし、すべての 'a'を取得していて、戻り値の型はarray型であり、それを文字列にしたいです。コードを修正する方法について何かアイデアはありますか?

ありがとう。

function randomPassword() {
    $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    for ($i = 0; $i < 8; $i++) {
        $n = Rand(0, count($alphabet)-1);
        $pass[$i] = $alphabet[$n];
    }
    return $pass;
}
170
nunos

セキュリティ警告Rand()は暗号学的に安全な疑似乱数ジェネレータではありません。 PHPで暗号学的に安全な疑似乱数列を生成する を探してください。

これを試してください(文字列のstrlenは常に1であるため、countの代わりにcountを使用します)。

function randomPassword() {
    $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < 8; $i++) {
        $n = Rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

デモ: http://codepad.org/UL8k4aYK

237
Neal

TL; DR:

  • 以下のrandom_int()と指定されたrandom_str()を使用してください。
  • random_int()がない場合は、 random_compat を使用してください。

説明:

パスワードを生成しているので、生成したパスワードが予測不可能であることを確認する必要があります。このプロパティが実装に存在することを確認する唯一の方法です。 暗号的に安全な疑似乱数ジェネレータ (CSPRNG)を使用することです。

CSPRNGの要件は、ランダム文字列の一般的なケースでは緩和できますが、セキュリティが関係している場合はそうではありません。

PHPでのパスワード生成に対する簡単で安全、そして正しい答えは RandomLib を使うことです。このライブラリは私だけでなく業界のセキュリティ専門家によっても監査されています。

あなた自身の解決策を発明することを好む開発者のために、PHP 7.0.0はこの目的のために random_int() を提供するでしょう。まだPHP 5.xを使用している場合は、 PHP 5 random_int()用のpolyfill を作成したので、PHP 7がリリースされる前に新しいAPIを使用できます。私たちのrandom_int() polyfillを使うのはあなた自身の実装を書くよりもおそらく安全です。

安全な乱数整数ジェネレータを用意しておくと、安全な乱数文字列を生成するのはpieよりも簡単です。

<?php
/**
 * Generate a random string, using a cryptographically secure 
 * pseudorandom number generator (random_int)
 * 
 * For PHP 7, random_int is a PHP core function
 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
 * 
 * @param int $length      How many characters do we want?
 * @param string $keyspace A string of all possible characters
 *                         to select from
 * @return string
 */
function random_str(
    $length,
    $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
) {
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    if ($max < 1) {
        throw new Exception('$keyspace must be at least two characters long');
    }
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}
107

私はあなたが特定の方法であなたのパスワードを生成しようとしていることを知っています、しかしあなたはこの方法も見たいと思うかもしれません...

$bytes = openssl_random_pseudo_bytes(2);

$pwd = bin2hex($bytes);

これはphp.netサイトから取得したもので、openssl_random_pseudo_bytes関数に入力した数の2倍の長さの文字列を作成します。そのため、上記は4文字のパスワードを作成します。

要するに...

$pwd = bin2hex(openssl_random_pseudo_bytes(4));

8文字のパスワードを作成します。

ただし、パスワードに含まれるのは数字0〜9と小文字の英字a〜fのみです。

103
user3260409

2行の小さなコード

デモ: http://codepad.org/5rHMHwnH

function Rand_string( $length ) {

    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return substr(str_shuffle($chars),0,$length);

}

echo Rand_string(8);

rand_stringを使用すると、作成する文字数を定義できます。

52
BSQ

一行で:

substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 )
36
Sandra

PHP 7を使用している場合は、 random_int() 関数を使用できます。

function generate_password($length = 20){
  $chars =  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
            '0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';

  $str = '';
  $max = strlen($chars) - 1;

  for ($i=0; $i < $length; $i++)
    $str .= $chars[random_int(0, $max)];

  return $str;
}

以下の古い答え:

function generate_password($length = 20){
  $chars =  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
            '0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';

  $str = '';
  $max = strlen($chars) - 1;

  for ($i=0; $i < $length; $i++)
    $str .= $chars[mt_Rand(0, $max)];

  return $str;
}
36
PeeHaa

あなたの最善の策はircmaxellによるRandomLibライブラリです。

使用例

$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));

$passwordLength = 8; // Or more
$randomPassword = $generator->generateString($passwordLength);

これはshuffle()Rand()のような通常の乱数関数よりも強い乱数の文字列を生成します(これはパスワード、ソルト、キーのような機密情報に一般的に欲しいものです)。

26
Madara Uchiha

既存の回答の中には近いものもありますが、次のいずれかがあるため、回答を投稿します。

  • 同じエントロピーでは、ブルートフォースが容易になるように、またはパスワードを長くする必要があるように、思っているよりも小さい文字スペース
  • a RNG これは暗号的に安全とは見なされません
  • いくつかのサードパーティ製のライブラリの要件と私はそれが自分でそれを行うのにかかるかもしれないものを示すことは面白いかもしれないと思った

生成されたパスワードのセキュリティ、少なくとも私見はあなたがそこに着く方法を超越するので、この答えはcount/strlen問題を回避するでしょう。私はPHP> 5.3.0も想定するつもりです。

問題を構成要素に分解しましょう。

  1. ランダムデータを取得するためにランダム性の安全なソースを使用する
  2. そのデータを使い、それを何らかの印刷可能な文字列として表現する

最初の部分として、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に使用されるエントロピープールを排出することが問題になる場合は、パディング文字=が中間結果のますます小さな割合を占めるようになります。

14
jeteon

定数countalphabetではなくstrlen($alphabet)が必要です('alphabet'と同等)。

ただし、Randはこの目的に適したランダム関数ではありません。それは暗黙のうちに現在の時刻でシードされているので、その出力は簡単に予測できます。さらに、Randは暗号的に安全ではありません。したがって、出力から内部状態を判断するのは比較的簡単です。

代わりに、/dev/urandomから読んで、暗号的にランダムなデータを取得してください。

14
phihag

base_convert(uniqid('pass', true), 10, 36);

例えば。 e0m6ngefmj4

EDIT

私がコメントで述べたように、その長さはブルートフォース攻撃がそれに対してタイミング攻撃よりよく働くだろうということを意味します、それでそれは「ランダムジェネレータがどれほど安全であるか」について心配することは本当に関係ありません。セキュリティ、特にこのユースケースでは、使いやすさを補完する必要があるため、上記のソリューションは実際には必要な問題に対して十分に有効です。

しかし、安全なランダムな文字列ジェネレータを探しているときにこの回答に出くわした場合(トークンを生成するような人もいると思うので)、このようなコードのジェネレータは次のようになります。

function base64urlEncode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function secureId($length = 32) {

    if (function_exists('openssl_random_pseudo_bytes')) {
        $bytes = openssl_random_pseudo_bytes($length);
        return rtrim(strtr(base64_encode($bytes), '+/', '0a'), '=');
    }
    else { // fallback to system bytes

        error_log("Missing support for openssl_random_pseudo_bytes");

        $pr_bits = '';

        $fp = @fopen('/dev/urandom', 'rb');
        if ($fp !== false) {
            $pr_bits .= @fread($fp, $length);
            @fclose($fp);
        }

        if (strlen($pr_bits) < $length) {
            error_log('unable to read /dev/urandom');
            throw new \Exception('unable to read /dev/urandom');
        }

        return base64urlEncode($pr_bits);
    }
}
11
srcspider

これは基本的にずっと単純なsubstr(md5(uniqid()), 0, 8);と同じです。

11
Explosion Pills

もう一つ(Linuxのみ)

function randompassword()
{
    $fp = fopen ("/dev/urandom", 'r');
    if (!$fp) { die ("Can't access /dev/urandom to get random data. Aborting."); }
    $random = fread ($fp, 1024); # 1024 bytes should be enough
    fclose ($fp);
    return trim (base64_encode ( md5 ($random, true)), "=");
}
9
Askarel

少し賢くなること:

function strand($length){
  if($length > 0)
    return chr(Rand(33, 126)) . strand($length - 1);
}

それをチェックしなさい ここ

8
Amir Forsati

この単純なコードを使用して、中程度の長さのパスワードを12文字以内で生成します。

$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);
6
Pablo Martinez

大文字、小文字、数字、特殊文字を使って試してください。

function generatePassword($_len) {

    $_alphaSmall = 'abcdefghijklmnopqrstuvwxyz';            // small letters
    $_alphaCaps  = strtoupper($_alphaSmall);                // CAPITAL LETTERS
    $_numerics   = '1234567890';                            // numerics
    $_specialChars = '`~!@#$%^&*()-_=+]}[{;:,<.>/?\'"\|';   // Special Characters

    $_container = $_alphaSmall.$_alphaCaps.$_numerics.$_specialChars;   // Contains all characters
    $password = '';         // will contain the desired pass

    for($i = 0; $i < $_len; $i++) {                                 // Loop till the length mentioned
        $_Rand = Rand(0, strlen($_container) - 1);                  // Get Randomized Length
        $password .= substr($_container, $_Rand, 1);                // returns part of the string [ high tensile strength ;) ] 
    }

    return $password;       // Returns the generated Pass
}

10桁のパスが必要だとしましょう。

echo generatePassword(10);  

出力例:

、IZCQ_IV\7

@wlqsfhT(d

1!8 + 1\4 @ uD

5
Sanjeev
  1. このコードを含むファイルを作成してください。
  2. コメントのように呼んでください。

    <?php 
    
    /**
    * @usage  :
    *       include_once($path . '/Password.php');
    *       $Password = new Password;
    *       $pwd = $Password->createPassword(10);
    *       return $pwd;
    * 
    */
    
    class Password {
    
        public function createPassword($length = 15) {
            $response = [];
            $response['pwd'] = $this->generate($length);
            $response['hashPwd'] = $this->hashPwd( $response['pwd'] );
            return $response;
        }
    
        private function generate($length = 15) {
            $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(){}/?,><";
            return substr(str_shuffle($chars),0,$length);
        }
    
        private function hashPwd($pwd) {
            return hash('sha256', $pwd);
        }
    
    }
    
    ?>
    
3
waz

クイックワンそれがあなたが望むものであれば、シンプルでクリーンで一貫したフォーマット

$pw = chr(mt_Rand(97,122)).mt_Rand(0,9).chr(mt_Rand(97,122)).mt_Rand(10,99).chr(mt_Rand(97,122)).mt_Rand(100,999);
3

これは、このページの別の回答に基づいています https://stackoverflow.com/a/21498316/525649

この答えは16進数文字0-9,a-fだけを生成します。 16進数のように見えないものについては、これを試してください:

str_shuffle(
  rtrim(
    base64_encode(bin2hex(openssl_random_pseudo_bytes(5))),
    '='
  ). 
  strtoupper(bin2hex(openssl_random_pseudo_bytes(7))).
  bin2hex(openssl_random_pseudo_bytes(13))
)
  • base64_encodeは、広範囲の英数字を返します。
  • rtrimは最後に=を削除することがあります

例:

  • 32eFVfGDg891Be5e7293e54z1D23110M3ZU3FMjb30Z9a740Ej0jz4
  • b280R72b48eOm77a25YCj093DE5d9549Gc73Jg8TdD9Z0Nj4b98760
  • 051b33654C0Eg201cfW0e6NA4b9614ze8D2FN49E12Y0zY557aUCb8
  • y67Q86ffd83G0z00M0Z152f7O2ADcY313Gd7a774fc5FF069zdb5b7

これは、ユーザー用のインターフェースを作成するための設定はあまりできませんが、いくつかの目的のためには大丈夫です。特殊文字の欠如を考慮して文字数を増やしてください。

3
Adam

より包括的で安全なパスワードスクリプトを作成しました。これは、2つの大文字、2つの小文字、2つの数字、および2つの特殊文字の組み合わせを作成します。合計8文字です。

$char = [range('A','Z'),range('a','z'),range(0,9),['*','%','$','#','@','!','+','?','.']];
$pw = '';
for($a = 0; $a < count($char); $a++)
{
    $randomkeys = array_Rand($char[$a], 2);
    $pw .= $char[$a][$randomkeys[0]].$char[$a][$randomkeys[1]];
}
$userPassword = str_shuffle($pw);
2
monrejames
//define a function. It is only 3 lines!   
function generateRandomPassword($length = 5){
    $chars = "123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
    return substr(str_shuffle($chars),0,$length);
}

//usage
echo generateRandomPassword(5); //random password legth: 5
echo generateRandomPassword(6); //random password legth: 6
echo generateRandomPassword(7); //random password legth: 7
0
hakiko

少なくとも1つの小文字、1つの大文字、1つの数字、および1つの特殊文字を含む長さ8の強力なパスワードを生成します。コードの長さも変更できます。

function checkForCharacterCondition($string) {
    return (bool) preg_match('/(?=.*([A-Z]))(?=.*([a-z]))(?=.*([0-9]))(?=.*([~`\!@#\$%\^&\*\(\)_\{\}\[\]]))/', $string);
}

$j = 1;

function generate_pass() {
    global $j;
    $allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_{}[]';
    $pass = '';
    $length = 8;
    $max = mb_strlen($allowedCharacters, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pass .= $allowedCharacters[random_int(0, $max)];
    }

    if (checkForCharacterCondition($pass)){
        return '<br><strong>Selected password: </strong>'.$pass;
    }else{
        echo 'Iteration '.$j.':  <strong>'.$pass.'</strong>  Rejected<br>';
        $j++;
        return generate_pass();
    }

}

echo generate_pass();
0
Zihad Ul Islam