PHPでパスワードをハッシュするためにbcryptをどのように使用しますか?


1255

「PHPにパスワードを保存するためにbcryptを使用する、bcryptルール」というアドバイスを時々聞いています。

しかし、何bcryptですか?PHPはそのような機能を提供していません。Wikipediaはファイル暗号化ユーティリティについて混乱しています。Web検索では、異なる言語でのBlowfishの実装がいくつか明らかになっています。現在、Blowfishはを介してPHPでも利用できますが、mcryptパスワードの保存にどのように役立ちますか?Blowfishは汎用の暗号であり、2つの方法で機能します。暗号化できた場合は、復号化できます。パスワードには一方向ハッシュ関数が必要です。

説明は何ですか?


13
この質問は以前に扱われており、標準ライブラリを使用するという彼らの提案は素晴らしいものです。セキュリティは複雑な問題であり、彼らが何をしているのかを知っている誰かによって設計されたパッケージを使用することによって、あなたは自分自身を助けているだけです。
eykanal

59
@eykanal -そのページもはるかに少ない、bcryptの言及説明していない、それが何でありますか
Vilx-

8
@eykanal-私はそれがどのように機能するかの説明を求めません。それが何であるか知りたいだけです。「bcrypt」というキーワードでネットで掘り下げることができるものは何でも、パスワードのハッシュに使用することはできません。とにかく直接ではなく、PHPではありません。了解しました。これで、Blowfishを使用してパスワードから派生したキーでパスワードを暗号化する(本質的にはそれ自体でパスワードを暗号化する)のは、実際には「phpass」パッケージであることを理解しました。しかし、それを「bcrypt」と呼ぶことは非常に誤解を招くものであり、それがこの質問で明確にしたかったことです。
Vilx

3
@Vilx:私は理由に関するより多くの情報を追加しましたbcrypt暗号化方式に対して一方向ハッシュアルゴリズムである私の回答でbcrypt完全に異なる鍵スケジュールがあり、暗号の初期状態(塩、ラウンド、鍵)を知らない限り、平文を暗号文から回復できないことを保証するとき、Blowfishだけであるというこの全体的な誤解があります。
Andrew Moore、

1
OpenwallのポータブルPHPパスワードハッシュフレームワーク(PHPass)もご覧ください。ユーザーパスワードに対する多くの一般的な攻撃に対して強化されています。
jww 2014年

回答:


1065

bcrypt(構成可能なラウンド数を介して)ハードウェアでスケーラブルなハッシュアルゴリズムです。その低速さと複数回のラウンドにより、攻撃者はパスワードを解読するために莫大な資金とハードウェアを配備する必要があります。パスワードごとのソルトbcryptREQUIRESソルト)に追加すると、途方もない量の資金やハードウェアがなければ、攻撃は事実上実行不可能であると確信できます。

bcryptEksblowfishアルゴリズムを使用してパスワードをハッシュします。EksblowfishBlowfishの暗号化フェーズはまったく同じですが、Eksblowfishのキースケジュールフェーズでは、後続の状態がソルトとキー(ユーザーパスワード)の両方に依存することが保証され、両方の知識がなければ状態を事前計算できません。この重要な違いにより、bcryptは一方向ハッシュアルゴリズムです。ソルト、ラウンド、キー(パスワード)を知らなければ、プレーンテキストのパスワードを取得することはできません。【出典

bcryptの使用方法:

PHP> = 5.5-DEVの使用

パスワードハッシュ関数がPHP> = 5.5に直接組み込まれました。これで、任意のパスワードのハッシュpassword_hash()を作成するために使用bcryptできます。

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

ユーザー提供のパスワードを既存のハッシュと照合するにはpassword_verify()、次のように使用できます。

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

PHP> = 5.3.7、<5.5-DEVを使用(RedHat PHP> = 5.3.3)

あり、互換性ライブラリGitHubのは、もともとCで記述された上記の関数のソースコードに基づい作成さには、同じ機能を提供ます。互換性ライブラリをインストールすると、使用法は上記と同じになります(5.3.xブランチを使用している場合は、配列の省略表記を差し引いてください)。

PHP <5.3.7の使用(非推奨)

crypt()関数を使用して、入力文字列のbcryptハッシュを生成できます。このクラスは自動的にソルトを生成し、既存のハッシュを入力に対して検証できます。5.3.7以降のバージョンのPHPを使用している場合は、組み込み関数またはcompatライブラリを使用することを強くお勧めします。この代替手段は、歴史的な目的でのみ提供されています。

class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input){
    $hash = crypt($input, $this->getSalt());

    if (strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash){
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt(){
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if ($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if (strlen($bytes) < $count) {
      $bytes = '';

      if ($this->randomState === null) {
        $this->randomState = microtime();
        if (function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for ($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input){
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (true);

    return $output;
  }
}

このコードは次のように使用できます。

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

または、Portable PHP Hashing Frameworkを使用することもできます。


7
@The Wicked Flea:残念なことにmt_rand()、現在の時刻と現在のプロセスIDを使用してシードされます。参照してくださいGENERATE_SEED()の中で/ext/standard/php_rand.h
Andrew Moore、

53
@マイク:どうぞ、それはまさにその理由のためにあります!
Andrew Moore、

14
getSalt関数の$ salt文字列の先頭を変更する必要があると考える人にとって、これは必要ありません。$ 2a $ __はCRYPT_BLOWFISHソルトの一部です。ドキュメントから:「次のソルトを使用したフグのハッシュ化:「$ 2a $」、2桁のコストパラメータ「$」、およびアルファベットからの22桁」。
jwinn 2011

18
@MichaelLang:良い点crypt()はピアレビューされ、検証されます。上記のコードcrypt()は、POSIX crypt()関数を呼び出すPHP を呼び出します。上記のすべてのコードは、を呼び出す前にランダムなソルトを生成します(暗号的に安全である必要はなく、ソルトは秘密とは見なされません)crypt()たぶん、オオカミに電話する前に、少し調べてみてください。
アンドリュームーア

31
この回答は良いものの、その年齢を示し始めていることに注意してください。このコード(に依存する他のPHP実装と同様crypt())は、5.3.7より前のセキュリティ脆弱性の影響を受け、(非常にわずかに)非効率な5.3.7以降です。関連する問題の詳細は、こちらで確認できます。また、新しいパスワードハッシュAPI後方互換lib)が、アプリケーションにbcryptパスワードハッシュを実装するための推奨される方法であることにも注意してください。
DaveRandom 2012

295

だから、あなたはbcryptを使いたいですか?驚くばかり!ただし、暗号化の他の領域と同様に、自分で行うべきではありません。キーの管理、ソルトの保存、乱数の生成などについて心配する必要がある場合は、間違っています。

その理由は簡単です。bcryptを台無しにするのは簡単なことです。実際、このページのほとんどすべてのコードを見ると、これらの一般的な問題の少なくとも1つに違反していることがわかります。

それに直面して、暗号化は難しいです。

専門家にお任せください。これらのライブラリを維持するのが仕事の人のために残してください。決定を下す必要がある場合、それは間違っています。

代わりに、ライブラリを使用してください。要件に応じていくつか存在します。

図書館

以下は、より一般的なAPIの内訳です。

PHP 5.5 API-(5.3.7以降で利用可能)

PHP 5.5以降、パスワードをハッシュするための新しいAPIが導入されています。5.3.7以降用に維持されている(私が)シム互換性ライブラリもあります。これは、ピアレビューおよびという利点がある簡単な使用への実装を。

function register($username, $password) {
    $hash = password_hash($password, PASSWORD_BCRYPT);
    save($username, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    if (password_verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

本当に、それは非常にシンプルであることを目指しています。

リソース:

Zend \ Crypt \ Password \ Bcrypt(5.3.2+)

これは、PHP 5.5に似た別のAPIであり、同様の目的を果たします。

function register($username, $password) {
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    $hash = $bcrypt->create($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    if ($bcrypt->verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

リソース:

PasswordLib

これは、パスワードハッシュに対する少し異なるアプローチです。PasswordLibは単にbcryptをサポートするのではなく、多数のハッシュアルゴリズムをサポートしています。これは主に、制御できない可能性があるレガシーシステムと異種システムとの互換性をサポートする必要がある状況で役立ちます。多数のハッシュアルゴリズムをサポートしています。5.3.2以降でサポートされています

function register($username, $password) {
    $lib = new PasswordLib\PasswordLib();
    $hash = $lib->createPasswordHash($password, '$2y$', array('cost' => 12));
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $lib = new PasswordLib\PasswordLib();
    if ($lib->verifyPasswordHash($password, $hash)) {
        //login
    } else {
        // failure
    }
}

参照:

  • ソースコード/ドキュメント:GitHub

PHPASS

これはbcryptをサポートする層ですが、PHP> = 5.3.2にアクセスできない場合に便利なかなり強力なアルゴリズムもサポートします。

function register($username, $password) {
    $phpass = new PasswordHash(12, false);
    $hash = $phpass->HashPassword($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $phpass = new PasswordHash(12, false);
    if ($phpass->CheckPassword($password, $hash)) {
        //login
    } else {
        // failure
    }
}

資源

注意: OpenwallでホストされていないPHPASSの代替を使用しないでこれらは別のプロジェクトです!!!

BCryptについて

気づいたら、これらのライブラリはすべて1つの文字列を返します。これは、BCryptが内部でどのように機能するかによるものです。そして、それについてたくさんの答えがあります。ここに私が書いたセレクションがあります。ここにはコピー/貼り付けしませんが、リンクします。

要約

多くの異なる選択肢があります。どちらを選ぶかはあなた次第です。ただし、これを処理するには、上記のライブラリのいずれかを使用することを強くお勧めします。

繰り返しますが、crypt()直接使用している場合は、おそらく何かが間違っています。コードがhash()(またはmd5()またはsha1())を直接使用している場合は、ほぼ間違いなく何かが間違っています。

ライブラリを使用するだけ...


7
ソルトはランダムに生成する必要がありますが、安全なランダムソースから取得する必要はありません。塩は秘密ではありません。次のソルトを推測できることは、実際のセキュリティに影響を与えません。暗号化されたパスワードごとに異なるソルトを生成するのに十分な大きさのデータプールからのものである限り、問題ありません。あなたのハッシュが悪手になった場合にレインボーテーブルを使用しないようにするために、塩がそこにあることを覚えておいてください。彼らは秘密ではありません。
Andrew Moore

7
@AndrewMoore絶対正解です!ただし、塩は統計的に一意になるのに十分なエントロピーを持っている必要があります。アプリケーションだけでなく、すべてのアプリケーションで。したがってmt_rand()、十分に高い周期がありますが、シード値は32ビットのみです。したがって、mt_rand()効果的に使用すると、32ビットのエントロピーのみに制限されます。これは誕生日の問題のおかげで、7kの生成された塩(全体)で50%の確率で衝突することになります。以来bcrypt塩の128ビットを受け入れ、それはすべての128ビット;-)供給できるソースを使用することをお勧めします。(128ビットでは、衝突の50%の確率で2e19ハッシュが発生します)...
ircmaxell 2013年

1
@ircmaxell:「十分に大きなデータのプール」を強調します。ただし、ソースは、非常に高いエントロピーソースである必要はなく、128ビットに十分な高さである必要があります。ただし、利用可能なすべてのソースを使い尽くし(OpenSSLを使用していないなど)、唯一のフォールバックがmt_rand()である場合は、代替手段(rand())よりも優れています。
Andrew Moore

4
@AndrewMoore:絶対に。それについては議論しません。ちょうどそれmt_randuniqid(ひいてはlcg_valuerand)最初の選択肢ではありません...
ircmaxell

1
ircmaxell、5.3.xxのpassword_compatライブラリに感謝します。これは以前は必要ありませんでしたが、5.3.xx phpサーバーでは必要になりました。このロジックを実行しないように明確なアドバイスをありがとう自分。
Lizardx

47

十分なレインボーテーブル:安全なパスワードスキームまたはポータブルPHPパスワードハッシュフレームワークについて知っておくべきこと」で、多くの情報を入手できます。

目標は、パスワードを遅いものでハッシュすることです。そのため、パスワードデータベースを取得している誰かがそれを総当たり攻撃しようとして死ぬことになります(パスワードをチェックするための10ミリ秒の遅延はあなたにとって何の意味もありません。Bcryptは低速であり、パラメーターと一緒に使用して、速度を選択できます。


7
あなたが望むものを何でも強制すると、ユーザーは何とかして失敗し、複数のものに同じパスワードを使用します。したがって、できる限り保護するか、パスワードを保存する必要のないもの(SSO、openIDなど)を実装する必要があります。
Arkh、2011年

41
いいえ。パスワードハッシュは1つの攻撃から保護するために使用されます。誰かがデータベースを盗んで、平文のログイン+パスワードを取得したいのです。
11

4
@Josh K. phpassを調整した後、いくつかの単純なパスワードをクラックして、Webサーバーでの計算に1ms〜10msかかるようにすることをお勧めします。
アーク、2011年

3
同意した。しかし、qwertyをパスワードとして使用するユーザーの種類は、複雑なものを彼(および攻撃者)が簡単に読み取ることができる場所にマークダウンする種類のユーザーでもあります。bcryptを使用すると、意志に反してデータベースが公開されると、1回のパスでsha512を使用する場合よりも、^ | $$&ZL6-£のようなパスワードを持っているユーザーにアクセスするのが難しくなります。
アーク

4
@coreywardは、ブロックしないよりも有害であることを指摘する価値があります。これは簡単に「サービス拒否」ベクトルと見なされます。既知のアカウントで不正なログインをスパムし始めるだけで、多くのユーザーを非常に簡単に妨害できます。特に有料の顧客の場合は、アクセスを完全に拒否するよりも、攻撃者をターピット(遅延)する方が適切です。
damianb 2012年

36

PHPのcrypt()関数を使用してbcryptで一方向のハッシュを作成し、適切なBlowfishソルトを渡すことができます。方程式全体で最も重要なのは、A)アルゴリズムが危険にさらされていないこと、およびB)各パスワードを適切にソルトすることです。アプリケーション全体のソルトを使用しないでください。これにより、アプリケーション全体が開かれ、1セットのRainbowテーブルから攻撃できるようになります。

PHP-暗号関数


4
これは正しいアプローチcrypt()です。いくつかの異なるパスワードハッシュ関数をサポートするPHPの関数を使用してください。CRYPT_STD_DESまたはを使用していないことを確認してくださいCRYPT_EXT_DES- または、サポートされている他のタイプのいずれでも問題ない(名前にbcryptが含まれているCRYPT_BLOWFISH)。
カフェ、2011年

4
実際、SHAには「rounds」オプションを介したコストパラメータもあります。それを使用するとき、bcryptを支持する理由もわかりません。
Pieter Ennes、2011

3
実際、パスワードの単一のSHA-1(またはMD5)は、ソルトの有無にかかわらず、ブルートフォースに簡単に対応できます(ソルトはブルートフォースではなくレインボーテーブルに対して役立ちます)。bcryptを使用します。
パウロEbermann

私は誰もがphpのcrypt()を意味するときに「bcrypt」と言うように思われるのは不安です。
Sliq 2013年

3
@パニックなぜですか?アルゴリズムはbcryptと呼ばれます。定数にcrypt対応するbcryptを使用して、いくつかのパスワードハッシュを公開しますCRYPT_BLOWFISH。Bcryptは現在サポートされている最も強力なアルゴリズムであり、Bcryptがサポートするcrypt他のいくつかのアルゴリズムは非常に弱いです。
CodesInChaos 2013年

34

編集:2013.01.15-サーバーがサポートする場合は、代わりにmartinstoeckliのソリューションを使用します。


誰もがこれをもっと複雑にしたいと思っています。crypt()関数はほとんどの作業を行います。

function blowfishCrypt($password,$cost)
{
    $chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt=sprintf('$2y$%02d$',$cost);
//For PHP < PHP 5.3.7 use this instead
//    $salt=sprintf('$2a$%02d$',$cost);
    //Create a 22 character salt -edit- 2013.01.15 - replaced rand with mt_rand
    mt_srand();
    for($i=0;$i<22;$i++) $salt.=$chars[mt_rand(0,63)];
    return crypt($password,$salt);
}

例:

$hash=blowfishCrypt('password',10); //This creates the hash
$hash=blowfishCrypt('password',12); //This creates a more secure hash
if(crypt('password',$hash)==$hash){ /*ok*/ } //This checks a password

明らかなはずですが、パスワードに「password」を使用しないでください。


3
ソルトの作成は改善される可能性があります(OSのランダムソースを使用)。そうでなければ、私には良さそうです。新しいバージョンのPHP 2yでは、の代わりに使用することをお勧めします2a
martinstoeckli 2013年

mcrypt_create_iv($size, MCRYPT_DEV_URANDOM)塩のソースとして使用します。
CodesInChaos 2013年

少しでもパフォーマンスが向上するはずの場合は、少し時間があればmcrypt_create_iv()を詳しく見ていきます。
Jon Hulka 2013年

2
Base64エンコーディングを追加し、カスタムアルファベットのbcrypt使用に変換します。mcrypt_create_iv(17, MCRYPT_DEV_URANDOM)str_replace('+', '.', base64_encode($rawSalt))$salt = substr($salt, 0, 22);
CodesInChaos

1
@JonHulka-PHPの互換性パック [行127]を見てください。これは簡単な実装です。
martinstoeckli 2013年

29

PHPのバージョン5.5には、BCrypt、関数password_hash()、およびのサポートが組み込まれていますpassword_verify()。実際、これらは関数のラッパーにすぎずcrypt()、正しく使用しやすくなります。安全なランダムソルトの生成を処理し、適切なデフォルト値を提供します。

この関数を使用する最も簡単な方法は次のとおりです。

$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

このコードは、BCrypt(アルゴリズム2y)でパスワードをハッシュし、OSのランダムソースからランダムなソルトを生成し、デフォルトのコストパラメーター(現時点では10)を使用します。2行目は、ユーザーが入力したパスワードが既に保存されているハッシュ値と一致するかどうかをチェックします。

コストパラメータを変更する場合は、次のようにしてコストパラメータを1増やし、ハッシュ値の計算に必要な時間を2倍にします。

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));

"cost"パラメータとは対照的に、"salt"関数はすでに暗号的に安全なソルトを作成するために最善を尽くしているため、パラメータを省略することが最善です。

PHPバージョン5.3.7以降では、関数を作成したのと同じ作者による互換性パックが存在しpassword_hash()ます。5.3.7より前のバージョンのPHP では、Unicode対応のBCryptアルゴリズムであるcrypt()with はサポートされていません2y。代わりにで置き換えることができ2aます。これは、以前のPHPバージョンの最良の代替手段です。


3
これを読んで最初に思ったのは「生成された塩をどうやって保存するのか」ということでした。ドキュメントを調べた後、password_hash()関数は、暗号化方式、ソルト、および生成されたハッシュを格納する文字列を生成します。したがって、password_verify()関数が機能するために必要なすべてのものを1つの文字列に格納するだけです。他の人がこれを見るときに役立つかもしれないので、これについて言及したかっただけです。
jzimmerman2011 2014

@ jzimmerman2011-正確には、別の答えで、このストレージ形式を例で説明しようとしました。
martinstoeckli 2014

7

現在の考え方:ハッシュは、可能な最速ではなく、利用可能な最も遅いはずです。これにより、レインボーテーブル攻撃が抑制されます

また、関連していますが、注意が必要です。攻撃者がログイン画面に無制限にアクセスすることはできません。それを防ぐには:すべてのヒットとURIを記録するIPアドレス追跡テーブルを設定します。ログインの試行が5分を超えても同じIPアドレスから5回を超える場合は、説明でブロックします。2番目のアプローチは、銀行のように2層のパスワード方式を使用することです。2回目のパスで障害に対するロックアウトを設定すると、セキュリティが向上します。

概要:時間のかかるハッシュ関数を使用して、攻撃者を遅くします。また、ログインへのアクセスをブロックし、2番目のパスワード階層を追加します。


彼らは攻撃者がすでに他の手段で私のDBを盗むことに成功しており、現在paypalなどで試すためにパスワードを取得しようとしていると思います。
Vilx- 2011

4
2012年の途中で、この答えはまだおかしいですが、低速ハッシュアルゴリズムはどのようにしてレインボーテーブル攻撃を防ぎますか?ランダムなバイト範囲のソルトがやったと思いましたか?ハッシュアルゴリズムの速度は、特定の時間内に取得したハッシュに対して送信できる反復の数を決定するものだといつも思っていました。また、失敗したログイン試行でユーザーをブロックすることは絶対にありません。ユーザーがうんざりすることを信じています。多くの場合、サイトによっては、パスワードを覚える前に5回近くログインする必要があります。また、第2段階の階層は機能しません。ただし、携帯電話のコードによる2段階認証は可能です。
Sammaye 2012

1
@Sammaye私はある程度これに同意します。ログインに5回失敗した場合にブロックを設定し、すぐに7に上げ、その後10回にして20にしました。通常のユーザーは20回のログイン試行に失敗するべきではありませんが、ブルートフォース攻撃を簡単に停止できるほど低い
Bruce Aldridge

@BruceAldridge私は個人的には、スクリプトをランダムに一時停止させてから、7回のログインに失敗し、ブロックするのではなくキャプチャを表示する方がよいと思います。ブロッキングは非常に積極的な行動です。
Sammaye 2012

1
@Sammaye私は永久的なブロックが悪いことに同意します。私は、失敗した試行の数とともに増加する一時的なブロックについて言及しています。
Bruce Aldridge 2012

7

これは、この古い質問に対する更新された回答です!

PHPでパスワードをハッシュする正しい方法は5.5以降であり、パスワードpassword_hash()を確認する正しい方法はでpassword_verify()あり、これはPHP 8.0でも同じです。これらの関数はデフォルトでbcryptハッシュを使用しますが、他のより強力なアルゴリズムが追加されています。password_hashパラメータを使用して、作業要素(効果的に暗号化の「強さ」)を変更できます。

ただし、bcryptはまだ十分に強力ですがbcryptは最新のものとは見なされなくなりましたArgon2と呼ばれる、より良いパスワードハッシュアルゴリズムのセットが到着しました。それらの違い(ここで説明されています):

Argon2には、Argon2idとArgon2dとArgon2iの2つの主要なバリアントがあります。Argon2dは、データに依存するメモリアクセスを使用するため、サイドチャネルタイミング攻撃の脅威がなく、暗号通貨や作業証明アプリケーションに適しています。Argon2iは、データに依存しないメモリアクセスを使用します。これは、パスワードハッシュおよびパスワードベースのキー導出に適しています。Argon2idは、メモリの最初の反復の前半ではArgon2iとして機能し、残りの部分ではArgon2dとして機能するため、サイドメモリ攻撃の保護と、時間とメモリのトレードオフによるブルートフォースコストの節約の両方を提供します。

Argon2iサポートはPHP 7.2で追加され、次のように要求します。

$hash = password_hash('mypassword', PASSWORD_ARGON2I);

そしてArgon2idのサポートはPHP 7.3で追加されました:

$hash = password_hash('mypassword', PASSWORD_ARGON2ID);

結果のハッシュ文字列には、作成時に使用されたアルゴリズム、ソルト、および作業要素に関する情報が含まれているため、パスワードの検証に変更は必要ありません。

libsodium(PHP 7.2で追加)はまったく個別に(そして多少冗長に)、sodium_crypto_pwhash_str ()and sodium_crypto_pwhash_str_verify()関数を介してArgon2ハッシュも提供します。これは、PHP組み込みとほぼ同じように機能します。これらを使用する理由の1つとして、PHPがlibargon2なしでコンパイルされることがあり、そのためArgon2アルゴリズムがpassword_hash関数で使用できなくなることがあります。PHP 7.2以降では常にlibsodiumが有効になっている必要がありますが、有効になっていない場合もありますが、そのアルゴリズムを使用するには、少なくとも2つの方法があります。libsodiumを使用してArgon2idハッシュを作成する方法は次のとおりです(PHP 7.2でも、Argon2idのサポートがない場合))。

$hash = sodium_crypto_pwhash_str(
    'mypassword',
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

手動でソルトを指定することはできないことに注意してください。これはlibsodiumの精神の一部です。ユーザーがparamsをセキュリティを危険にさらす可能性のある値に設定できないようにしてください。たとえば、空のソルト文字列をPHPのpassword_hash関数に渡すことを妨げるものはありません。libsodiumはあなたにそんな馬鹿なことをさせません!



1

データベースにクリアテキストでパスワードを保存することは安全ではありません。bcryptはハッシュパスワード技術であり、パスワードセキュリティを構築するために使用されます。bcryptの驚くべき機能の1つは、パスワードがbcryptされた形式で保存されるため、ハッキング攻撃からパスワードを保護するために使用されるハッカーから私たちを救うことです。

password_hash()関数は、新しいパスワードハッシュを作成するために使用されます。強力で堅牢なハッシュアルゴリズムを使用します。password_hash()関数は、crypt()関数と非常に互換性があります。したがって、crypt()によって作成されたパスワードハッシュはpassword_hash()で使用でき、その逆も可能です。関数password_verify()とpassword_hash()は、関数crypt()のラッパーにすぎず、正確に使用することがはるかに簡単になります。

構文

string password_hash($password , $algo , $options)

現在、次のアルゴリズムがpassword_hash()関数でサポートされています。

PASSWORD_DEFAULT PASSWORD_BCRYPT PASSWORD_ARGON2I PASSWORD_ARGON2ID

パラメータ:この関数は、上記および下記の3つのパラメータを受け入れます。

password:ユーザーのパスワードを格納します。 algo:パスワードのハッシュが行われるときに使用されるアルゴリズムを示しながら、継続的に使用されるパスワードアルゴリズム定数です。 optionsオプションを含む連想配列です。これが削除されて含まれていない場合、ランダムなソルトが使用され、デフォルトのコストが使用されます。 戻り :成功した場合はハッシュされたパスワードを、失敗した場合はFalseを返します。

Input : echo password_hash("GFG@123", PASSWORD_DEFAULT); Output : $2y$10$.vGA19Jh8YrwSJFDodbfoHJIOFH)DfhuofGv3Fykk1a

以下のプログラムは、PHPのpassword_hash()関数を示しています。

<?php echo password_hash("GFG@123", PASSWORD_DEFAULT); ?>

出力

$2y$10$Z166W1fBdsLcXPVQVfPw/uRq1ueWMA6sLt9bmdUFz9AmOGLdM393G

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.