Help us understand the problem. What is going on with this article?

password_hash()とpassword_verify()を用いた暗号化と認証の方法について

More than 3 years have passed since last update.

PHPでログインフォーム付きのWebアプリを開発されている方は多いと思います。
ユーザ情報を管理する際にパスワードを平文で管理しているとセキュリティ上、好ましくないため暗号化しておくべきですが、暗号化の方法は様々です。
PHPの公式ドキュメントによれば、SHA1MD5による暗号化は不適切であり、最近ではcrypt()password_hash()を用いて暗号化することが好ましいとされています。

password_hash()password_verify()を組み合わせればお手軽に暗号化と認証の仕組みを実装できます。

password_hash()password_verify()の使い方については様々な解説がありましたが、ユーザアカウント作成時にパスワードを暗号化する手順と、ログイン時にユーザ情報を認証する手順が、流れとして紹介されているものが少ない印象だったため、DBへの情報追加などの一連の手順を踏まえて記述したいと思います。

ユーザ情報の登録画面

index.html
<!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>

ユーザ情報の登録(パスワードの暗号化)

create_user_info.php
<?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の公式ドキュメントの定義済み定数をご確認ください。

ログイン画面

pass_check.html
<!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>

ユーザ情報の認証(暗号化済みの文字列との比較)

pass_check.php
<?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

MasaKu_n
Webにまつわる技術や情報について学習します
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした