サーチ…


前書き

より安全なWebサービスがパスワードをプレーンテキスト形式で保存するのを避けるため、PHPなどの言語は、より安全な業界標準をサポートするためのさまざまな(解読不能な)ハッシュ関数を提供します。このトピックでは、PHPで適切なハッシングを行うためのドキュメントを提供します。

構文

  • string password_hash ( string $password , integer $algo [, array $options ] )
  • boolean password_verify ( string $password , string $hash )
  • boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
  • array password_get_info ( string $hash )

備考

PHP 5.5より前のバージョンで、互換性パックを使用してpassword_*関数を提供することができpassword_* 。できるだけ互換性パックを使用することを強くお勧めします。

互換性パックの有無にかかわらず、 crypt()による正しいBcrypt機能はPHP 5.3.7以降に依存します。そうしないと、パスワードをASCII文字のみの文字セットに制限する必要あります。

注: PHP 5.5以降を使用している場合、 サポートされていないバージョンのPHPを使用してます。これは、セキュリティアップデートをもう受信しません。できるだけ早く更新してください。その後、パスワードハッシュを更新することができます。

アルゴリズムの選択

安全なアルゴリズム

安全でないアルゴリズム

以下のハッシュアルゴリズムは、目的に 応じ安全でないか、または不適当であるため使用しないでください 。それらは、パスワードハッシュには適していませんでした。なぜなら、パスワードのハッシュを遅くて難しくするのではなく、速いダイジェスト用に設計されていたからです。

いずれかを使用する場合は 、塩類も含めできるだけ早く推奨される安全なアルゴリズムに切り替える必要があります。

安全でないと考えられるアルゴリズム:

いくつかのアルゴリズムは、信頼性を証明するメッセージダイジェストアルゴリズムとして安全に使用できますが、 決してパスワードハッシングアルゴリズムとしては使用できません

  • SHA-2
  • SHA-3

SHA256やSHA512などの強力なハッシュは途切れにくく、堅牢ですが、 bcryptargon2ハッシュ関数を使用する方が一般的に安全です。これらのアルゴリズムに対するブルートフォース攻撃は従来のコンピュータでは非常に困難です。

既存のパスワードハッシュをより強力なアルゴリズムにアップグレードできるかどうかを判断する

PASSWORD_DEFAULTメソッドを使用してシステムにパスワードをハッシュする最適なアルゴリズムを選択させる場合、強度がデフォルトで増加するため、ユーザーのログイン時に古いパスワードを再ハッシュしたい場合があります

<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {

    // now determine if the existing hash was created with an algorithm that is
    // no longer the default
    if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {

        // create a new hash with the new default
        $newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);

        // and then save it to your data store
        //$db->update(...);
    }
}
?>

システムでpassword_ *関数が利用できない場合(以下の注釈にリンクされている互換性パックを使用することはできません)、アルゴリズムを決定して、次のような方法で元のハッシュを作成することができます。

<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
    echo 'Algorithm is Bcrypt';
    // the "cost" determines how strong this version of Bcrypt is
    preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
    $cost = $matches[1];
    echo 'Bcrypt cost is '.$cost;
}
?>

パスワードハッシュの作成

password_hash()を使用して、現在の業界ベストプラクティスの標準ハッシュまたはキー派生を使用して、パスワードハッシュを作成します。書面では、標準はbcryptです。つまり、 PASSWORD_DEFAULTにはPASSWORD_DEFAULTと同じ値が含まれPASSWORD_BCRYPTます。

$options = [
    'cost' => 12,
];

$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);

3番目のパラメータは必須ではありません

'cost'値は、運用サーバーのハードウェアに基づいて選択する必要があります。パスワードを増やすと、パスワードを生成するコストが高くなります。高価な人はそれを生成するためにそれを分解しようとする誰もがかかるように長い時間を生成することです。理想的には、コストは可能な限り高くする必要がありますが、実際にはすべてを遅くしないように設定する必要があります。 0.1秒から0.4秒の間のどこかに問題はありません。疑義がある場合は、デフォルト値を使用してください。

5.5

5.5.0より小さいPHPでは、 password_*関数は利用できません。これらの機能を置き換えるには、互換性パックを使用する必要があります。互換性パックには、PHP 5.3.7以降、または$2y修正がバックポートされたバージョン(RedHatなど)が必要です。

それらを使用できない場合は、 crypt()パスワードハッシュを実装できます。password_hash password_hash()crypt()関数のラッパーとして実装されているため、機能を失う必要はありません。

// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation

// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
    $salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
    $salt = base64_encode($salt);
    // crypt uses a modified base64 variant
    $source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    $dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt = strtr(rtrim($salt, '='), $source, $dest);
    $salt = substr($salt, 0, 22);
    // `crypt()` determines which hashing algorithm to use by the form of the salt string
    // that is passed in
    $hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}

パスワードハッシュ用の塩

暗号アルゴリズムの信頼性にもかかわらず、まだレインボーテーブルに対する脆弱性が存在します。それがを使うことが推奨される理由です。

saltとは、ハッシングの前にパスワードに付加されてソース文字列を一意にするものです。 2つの同一のパスワードが与えられた場合、結果として得られるハッシュは、その塩が一意であるためユニークなものになります。

ランダムな塩は、パスワードセキュリティの最も重要な部分の1つです。これは、既知のパスワードハッシュのルックアップテーブルであっても、ランダムな塩が使用されているため、攻撃者はデータベースのパスワードハッシュとユーザーのパスワードハッシュを一致させることができないことを意味します。あなたはいつも無作為かつ暗号的に安全な塩を使用するべきです。 続きを読む

password_hash() bcryptアルゴリズムを使用すると、結果のハッシュと一緒にプレーンテキストソルトが保存されます。つまり、ハッシュを異なるシステムやプラットフォームで転送して元のパスワードと照合することができます。

7.0

これが推奨されていない場合でも、 saltオプションを使用して独自のランダムな塩を定義することができます。

 $options = [
        'salt' => $salt, //see example below
 ];

重要です。このオプションを省略すると、パスワードハッシュごとにpassword_hash()によってランダムなsaltが生成されます。これが意図された動作モードです。

7.0

saltオプションは、PHP 7.0.0以降で廃止されました。既定で生成される塩を単に使用することが今や好ましい。

ハッシュに対してパスワードを確認する

password_verify()は、既知のハッシュに対するパスワードの有効性を検証するために提供される組み込み関数password_verify() PHP 5.5以降)。

<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
    echo 'Valid Password';
}
else {
    echo 'Invalid Password.';
}
?>

サポートされているすべてのハッシュアルゴリズムは、ハッシュ自体で使用されたハッシュを識別する情報を格納するため、平文パスワードをエンコードするために使用するアルゴリズムを指定する必要はありません。

あなたのシステムでpassword_ *関数が利用できない場合(以下の注釈にリンクされている互換性パックを使用することはできません)、 crypt()関数を使ってパスワード検証を実装することができます。 タイミング攻撃を避けるために、特定の予防策を講じなければならないことに注意してください。

<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
    // `crypt()` discards all characters beyond the salt length, so we can pass in
    // the full hashed password
    $hashedCheck = crypt($plaintextPassword, $hashedPassword);

    // this a basic constant-time comparison based on the full implementation used
    // in `password_hash()`
    $status = 0;
    for ($i=0; $i<strlen($hashedCheck); $i++) {
        $status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
    }

    if ($status === 0) {
        echo 'Valid Password';
    }
    else {
        echo 'Invalid Password';
    }
}
?>


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow