web-dev-qa-db-ja.com

crypt()およびpassword_hash()関数を使用して暗号化した後、パスワードが一致しません

古い投稿を変更しました。 crypt()関数を試し、password_hash()およびpassword_verify()を使用して、データベースからの暗号化されたパスワードを確認しようとしましたが、呼び出しごとに、password_hash()関数が異なる暗号化文字列を再調整し、password_verify()がそれに一致しません。

これが私がこれをしている方法です。

 //please ignore the syntax error if any

$data = '11';
$dbpass = password_hash($data, PASSWORD_BCRYPT);
echo $dbpass;  // displays the random strings on each page refresh.

パスワードがデータベースに保存されると、ログインプロセス中に一致しなくなります。以下は私の実際の機能です。

   private function process_data($password){
    $password = __STR.$password.__STR;
    return  password_hash($password, PASSWORD_BCRYPT);

  }
  private function processed($login_password, $dbpassword){
    $login_password = __STR.$login_password.__STR;
    return password_verify($login_password, $dbpassword);
  }

パスワードのハッシュ文字列を作成するための各関数呼び出しで、関数は次回は異なる文字列を返します。

12
Hunza Ali

では、これを1つずつ見ていきましょう。

まず、暗号化ではなく、ハッシュです。暗号化は双方向であり、ハッシュは一方向です。ハッシュしたい。暗号化したくありません。はい、用語は重要です。正しい用語を使用してください。

次に、_password_hash_への各呼び出しはsupposedであり、異なるハッシュを返します。それは強いランダムな塩を生成しているからです。これが設計方法であり、実際に使用する方法です。

さらに、DO NOTは、パスワードの前後に___STR_を追加するという「コショウ」のことをしません。あなたは何もしていないが、ユーザーのパスワードを弱める可能性がある(これは良くない)。それが悪い考えである理由に関する詳細情報が必要な場合: この回答を読んでください

続けて、cryptを直接使用しないことを強くお勧めします。実際、驚くほど簡単に台無しにして、非常に弱いハッシュを生成することができます。これが、_password_*_ apiが設計された理由です。 cryptは低レベルのライブラリであり、コードで高レベルのライブラリを使用する必要があります。 bcryptを台無しにする方法の詳細については、私のブログをチェックしてください: Bcryptを台無しにする7つの方法

Password APIは、シンプルなワンストップショップとして設計されました。それが機能しない場合は、次のことを確認してください。

  1. PHP> = 5.5.0を使用していますか?またはPHP> = 5.3.7 with password_compat を使用していますか?

    1. データベースの列の幅は十分ですか?

      少なくとも60文字の長さである必要があります。

    2. 関数の結果がbool(false)ではなく文字列であることを確認していますか?

      内部エラーがある場合は、_password_hash_から非文字列を返します。

    3. エラーが発生していますか?

      _error_reporting_を最大設定にオンにして(すべてをキャッチするには_-1_をお勧めします)、コードがエラーをスローしていないことを確認しましたか?

    4. 正しく使用していますか?

      _function saveUser($username, $password) {
          $hash = password_hash($password, PASSWORD_BCRYPT);
          // save $username and $hash to db
      }
      function login($username, $password) {
          // fetch $hash from db
          return password_verify($password, $hash);
      }
      _

      それぞれを1回だけ呼び出す必要があることに注意してください。

  2. PHP <5.3.7 with password_compat ?を使用していますか?そうであれば、これが問題です。サポートされていないバージョンのPHPで互換性ライブラリを使用しています。動作させる(特定のRedHatディストリビューションが必要な修正をバックポートしている)が、サポートされていないバージョンを使用している。妥当なリリースにアップグレードしてください。

他のすべてが失敗した場合は、このコードを実行して出力を報告してみてください。

_$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
$test = crypt("password", $hash);
$pass = $test == $hash;

echo "Test for functionality of compat library: " . ($pass ? "Pass" : "Fail");
echo "\n";
_

それがFailを返す場合は、サポートされていないバージョンのPHPを実行しているため、アップグレードする必要があります。passが返される場合は、ロジックのどこかにエラーがあります(ライブラリは正常に機能しています)。 )。

45
ircmaxell

パスワードを保存する最良の方法は、PHPの関数 password_hash() を使用することです。パスワードごとに暗号で安全なソルトを自動的に生成し、結果の60文字の文字列に含めます。塩の心配は一切ありません!

_// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
_

独自のスキームは非常に弱く、最初にパスワードハッシュを生成するには速すぎるMD5を使用し、次に静的ソルトを使用します。これはソルトの目的を無効にします。 パスワードを安全に保存する についての私のチュートリアルを見てみたいと思うかもしれません。

更新された質問に答えるために編集:

パスワードに___STR_を追加する必要はありません(ペッパーを追加したい場合は、より良い方法があります)が、サンプル関数は実際に機能するはずです。 password_hash()の戻り値は、ランダムなソルトのために毎回異なります。これは正しいです。関数password_verify()は検証のためにこのソルトを抽出できます。あなたの場合、データベースフィールドがおそらく問題です。 60文字の文字列を保持できることを確認してください。

1
martinstoeckli