パスワードハッシュを作る

# password_hash

(PHP 5 >= 5.5.0, PHP 7)

password_hash — パスワードハッシュを作る

### 説明

password_hash ( string `$password` , integer `$algo` [, array `$options` ] ) : string

password_hash() は、強力な一方向ハッシュアルゴリズムを使って 新しいパスワードハッシュを作ります。 password_hash() は crypt() と互換性があるので、 crypt() が作ったパスワードハッシュは password_hash() でも使えます。

現在、これらのアルゴリズムに対応しています。

- `PASSWORD_DEFAULT` - bcrypt アルゴリズムを使います (PHP 5.5.0 の時点でのデフォルトです)。 新しくてより強力なアルゴリズムが PHP に追加されれば、 この定数もそれにあわせて変わっていきます。 そのため、これを指定したときの結果の長さは、変わる可能性があります。 したがって、結果をデータベースに格納するときにはカラム幅を 60 文字以上にできるようなカラムを使うことをお勧めします (255 文字くらいが適切でしょう)。
- `PASSWORD_BCRYPT` - `CRYPT_BLOWFISH` アルゴリズムを使ってハッシュを作ります。これは標準の crypt() 互換のハッシュで、識別子 "$2y$" を使った場合の結果を作ります。 その結果は、常に 60 文字の文字列になります。失敗した場合に `FALSE` を返します。

サポートするオプション

- salt - パスワードのハッシュに使うソルトを手動で設定します。 これは、自動生成されたソルトを上書きすることに注意しましょう。

  省略した場合は、パスワードをハッシュするたびに password_hash() がランダムなソルトを自動生成します。これは意図したとおりの操作モードです。

  警告

  このソルト・オプションは、PHP 7.0.0 で非推奨になりました。 このオプションは指定せずに、デフォルトで生成されるソルトを使うことを推奨します。

- cost - 利用するアルゴリズムのコストを表します。 値の例については crypt() のページを参照ください。

  省略した場合のデフォルトは 10 です。この値でもかまいませんが、 ハードウェアの性能が許すならもう少し高くすることもできます。

### パラメータ

`password`

  ユーザーのパスワード。

  警告

  `PASSWORD_BCRYPT` をアルゴリズムに指定すると、 `password` が最大 72 文字までに切り詰められます。

`algo`

  パスワードのハッシュに使うアルゴリズムを表す パスワードアルゴリズム定数。

`options`

  オプションを含む連想配列。各アルゴリズムがサポートするオプションについては、 パスワードアルゴリズム定数 のページを参照ください。

  省略した場合は、ランダムな salt を生成してデフォルトのコストを使います。

### 返り値

ハッシュしたパスワードを返します。失敗した場合に `FALSE` を返します。

使ったアルゴリズムやコスト、そしてソフトもハッシュの一部として返されます。 つまり、ハッシュを検証するために必要な情報は、すべてそこに含まれているということです。 そのため、password_verify() でハッシュを検証するときに、 ソルトやアルゴリズムの情報を別に保存する必要はありません。

### 例

例1 password_hash() の例

`<?php
/**
* デフォルトのアルゴリズムを使ってパスワードをハッシュします。
* 現時点でのデフォルトは BCRYPT で、その結果は 60 文字になります。
*
* デフォルトは、今後変わる可能性があることに注意しましょう。結果が
* 60 文字以上になっても対応できるようにしておきましょう (255 あたりが適切です)
*/
echo password_hash("rasmuslerdorf", PASSWORD_DEFAULT)."\n";
?>`

上の例の出力は、 たとえば以下のようになります。

    $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

例2 password_hash() で、コストを手動で設定する例

`<?php
/**
* この例では、BCRYPT のコストをデフォルトより上げて、12 にします。
* また、アルゴリズムを BCRYPT に変えたことにも注目しましょう。結果は常に 60 文字になります。
*/
$options = [
'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>`

上の例の出力は、 たとえば以下のようになります。

    $2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K

例3 password_hash() で、ソルトを手動で設定する例

`<?php
/**
* ここでは、ソルトをランダムに生成するようにしています。
* 固定のソルトを使ったり、ランダムではない方法で作ったソルトを使ったりしてはいけません。
*
* 利用例の大半にあわせて、password_hash にランダムなソルトを生成させます。
*/
$options = [
'cost' => 11,
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM),
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>`

上の例の出力は、 たとえば以下のようになります。

    $2y$11$q5MkhSBtlsJcNEVsYh64a.aCluzHnGog7TQAKVmQwO9C8xb.t89F.

例4 password_hash() で、適切なコストを探す例

`<?php
/**
* このコードは、サーバーをベンチマークして、どの程度のコストに耐えられるかを判断します。
* サーバーに負荷をかけすぎない範囲で、できるだけ高めのコストを設定したいものです。
* 基準として 8 から 10 程度からはじめ、サーバーが十分に高速なら、できるだけ上げていきましょう。
* 以下のコードでは、ストレッチングの時間を 50 ミリ秒以内にすることを狙っています。
* 対話形式のログインを扱う際の許容時間としては、このあたりが妥当なところでしょう。
*/
$timeTarget = 0.05; // 50 ミリ秒
$cost = 8;
do {
$cost++;
$start = microtime(true);
password_hash("test", PASSWORD_BCRYPT, ["cost" => $cost]);
$end = microtime(true);
} while (($end - $start) < $timeTarget);
echo "Appropriate Cost Found: " . $cost . "\n";
?>`

上の例の出力は、 たとえば以下のようになります。

    Appropriate Cost Found: 10

### 注意

警告

この関数で使うソルトを自前で設定するのはお勧めしません。 ソルトを省略すれば、安全なソルトをこの関数が自動的に作ってくれます。

先述のとおり、PHP 7.0 で salt オプションを指定すると、 非推奨の警告が発生します。ソルトを手動で設定する仕組みは、将来のリリースで廃止されるかもしれません。

> 注意:

> 実際にサーバー上でこの関数をテストして、コストパラメータの適切な設定値を調整することをお勧めします。 対話型のシステムなら、関数の実行時間が 100 ミリ秒くらいに収まるくらいが適切です。 先ほどの例のスクリプトは、自分のハードウェア上での適切なコストを判断するための助けとなるでしょう。

> 注意: この関数がサポートするアルゴリズムの更新 (あるいはデフォルトのアルゴリズムの変更) は、必ず次の手順にのっとって行われます。

> - 新しく追加されたアルゴリズムがデフォルトになるまでには、 少なくとも一度は PHP のフルリリースを経ること。 つまり、たとえば、新しいアルゴリズムが 7.5.5 で追加されたとすると、 そのアルゴリズムがデフォルトになるのは早くても 7.7 以降ということになります (7.6 は、最初のフルリリースだからです)。 しかし、もし別のアルゴリズムが 7.6.0 で追加されたとすると、 そのアルゴリズムも 7.7.0 の時点でデフォルトになる資格を得ます。
> - デフォルトを変更できるのはフルリリース (7.3.0 や 8.0.0 など) のときだけで、リビジョンリリースでは変更できない。 唯一の例外は、現在のデフォルトにセキュリティ上の致命的な欠陥が発覚した場合の緊急リリースです。

### 参考

- password_verify() - パスワードがハッシュにマッチするかどうかを調べる
- crypt() - 文字列の一方向のハッシュ化を行う
- » ユーザーランドでの実装