password_hash関数
実は、md5関数とそれを使ったパスワードのソルト(salt)付与は、古い方法とみなされています。
これらを学んだのは、今後の内容を理解してもらうためと、他人のプロジェクトでこの方法に出会う可能性があるからです。
より洗練された方法でソルト付きパスワードを得る方法があります。そのために使われるのが
password_hash関数です。最初のパラメータとして文字列を受け取り、二番目のパラメータとして暗号化アルゴリズムを指定し(後述)、その文字列のソルト付きハッシュを返します。
次のコードを何度か実行してみてください:
<?php
echo password_hash('12345', PASSWORD_DEFAULT);
?>
実行するたびに異なる結果が得られ、その結果の最初の部分がソルト、二番目の部分がソルト付きパスワードとなります。
password_hash関数から得られたハッシュと、何らかのパスワードがあるとします。
これがそのパスワードのハッシュかどうかを確認するには、
password_verify関数を使うべきです。
この関数は最初のパラメータとしてパスワードを、二番目のパラメータとしてハッシュを受け取り、trueまたはfalseを返します。
例を見てみましょう:
<?php
$password = '12345'; // パスワード
$hash = '$2y$10$xoYFX1mFPxBSyxaRe3iIRutxkIWhxGShzEhjYUVd3qpCUKfJE1k7a'; // ハッシュ
if (password_verify($password, $hash)) {
// このパスワードからのハッシュです
} else {
// このパスワードからのハッシュではありません
}
?>
これが実際に何をもたらすかというと:データベースにソルトを保存するための別のフィールドを作成したり、このソルトを生成することに悩んだりする必要がなくなります。PHPがすべてをやってくれます!
つまり、データベースのpasswordフィールドには、ソルト付きパスワードをそのソルトと共に保存することになります。
ただし、ハッシュ化されたパスワードはより長い長さになります。
そのため、データベースではパスワードフィールドのサイズを修正し、60文字に設定する必要があります。
では、登録コードを修正しましょう。 現在のコードは以下の通りです:
<?php
function generateSalt()
{
$salt = '';
$saltLength = 8; // ソルトの長さ
for($i = 0; $i < $saltLength; $i++) {
$salt .= chr(mt_rand(33, 126)); // ASCII-tableからの文字
}
return $salt;
}
$salt = generateSalt(); // ソルト
$password = md5($salt . $_POST['password']); // パスワードをソルト付きハッシュに変換
?>
password_hashを使うと、次のように簡略化できます:
<?php
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
?>
同様に、認証コードも修正されます:
<?php
$login = $_POST['login'];
$query = "SELECT * FROM users WHERE login='$login'"; // ログインからユーザーを取得
$res = mysqli_query($link, $query);
$user = mysqli_fetch_assoc($res);
if (!empty($user)) {
$hash = $user['password']; // データベースからのソルト付きパスワード
// データベースのハッシュと入力されたパスワードの一致を確認
if (password_verify($_POST['password'], $hash)) {
// すべてOK、認証...
} else {
// パスワードが一致しません、メッセージを表示
}
} else {
// そのログインのユーザーはいません、メッセージを表示
}
?>
あなたの認証と登録を、新しく学んだ関数に変更してください。