PHPでログインフォーム付きのWebアプリを開発されている方は多いと思います。
ユーザ情報を管理する際にパスワードを平文で管理しているとセキュリティ上、好ましくないため暗号化しておくべきですが、暗号化の方法は様々です。
PHPの公式ドキュメントによれば、SHA1
やMD5
による暗号化は不適切であり、最近ではcrypt()
やpassword_hash()
を用いて暗号化することが好ましいとされています。
password_hash()
とpassword_verify()
を組み合わせればお手軽に暗号化と認証の仕組みを実装できます。
password_hash()
とpassword_verify()
の使い方については様々な解説がありましたが、ユーザアカウント作成時にパスワードを暗号化する手順と、ログイン時にユーザ情報を認証する手順が、流れとして紹介されているものが少ない印象だったため、DBへの情報追加などの一連の手順を踏まえて記述したいと思います。
##ユーザ情報の登録画面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ユーザ情報の登録画面</title>
</head>
<body>
<p>ユーザ情報</p>
<form action="create_user_info.php" method="post">
ID:<input type="text" name="id"><br>
PASS:<input type="text" name="pass">
<input type="submit" value="送信">
</form>
</body>
</html>
##ユーザ情報の登録(パスワードの暗号化)
<?php
//パスワードの暗号化
$hash_pass = password_hash($_POST['pass'], PASSWORD_DEFAULT);
// 接続するデータベースの情報
$dsn = 'pgsql:dbname=dbname host=localhost port=5432';
$user = 'user';
$password = 'password';
try {
// データベースへの接続開始
$dbh = new PDO($dsn, $user, $password);
// bindParamを利用したSQL文の実行
$sql = 'INSERT INTO table_name (id, pass) VALUES(:id, :pass);';
$sth = $dbh->prepare($sql);
$sth->bindParam(':id', $_POST['id']);
$sth->bindParam(':pass', $hash_pass);
$sth->execute();
// データベースへの接続に失敗した場合
} catch (PDOException $e) {
print('接続失敗:' . $e->getMessage());
die();
}
?>
平文のパスワードを暗号化しているpassword_hash($_POST['pass'], PASSWORD_DEFAULT);
の箇所ですが、第一引数には暗号化したい文字列を指定、第二引数ではハッシュアルゴリズムを指定します。
第二引数として、PASSWORD_DEFAULTを設定しておけば、インストールしているPHPのバージョンにおいて最も適切なハッシュアルゴリズムがデフォルトで設定されるようです。
詳しくはPHPの公式ドキュメントの定義済み定数をご確認ください。
##ログイン画面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ログイン画面</title>
</head>
<body>
<form action="pass_check.php" method="post">
ID:<input type="text" name="id"><br>
PASS:<input type="text" name="pass">
<input type="submit" value="ログイン">
</form>
</body>
</html>
##ユーザ情報の認証(暗号化済みの文字列との比較)
<?php
// 接続するデータベースの情報
$dsn = 'pgsql:dbname=dbname host=localhost port=5432';
$user = 'user';
$password = 'password';
try {
// データベースへの接続開始
$dbh = new PDO($dsn, $user, $password);
// bindParamを利用したSQL文の実行
$sql = 'SELECT pass FROM table_name WHERE id = :id;';
$sth = $dbh->prepare($sql);
$sth->bindParam(':id', $_POST['id']);
$sth->execute();
$pass = $sth->fetch();
//認証処理
if(password_verify($_POST['pass'], $pass['pass'])){
print '認証成功';
}else{
print '認証失敗';
}
// データベースへの接続に失敗した場合
} catch (PDOException $e) {
print('接続失敗:' . $e->getMessage());
die();
}
?>
認証処理を行っているpassword_verify($_POST['pass'], $pass['pass'])
の箇所ですが、第一引数には認証する文字列を指定、第二引数では暗号化済みの文字列を指定します。
password_verify
が平文で入力された文字列と暗号化済みの文字列がマッチするかを確かめます。
PHPのコードを理解しようとするよりも、暗号化の仕組みが理解できれば流れもつかみやすいかと思いますので、PHPの公式ドキュメントを読みながら理解を進めると良いかもしれません。
##参考:
安全なパスワードハッシュ
http://php.net/manual/ja/faq.passwords.php