【PHP】パスワードのハッシュ化とパスワードの認証をする方法

# はじめに
- パスワードのハッシュ化とパスワードの認証をする方法について本やネットの情報から調べて理解したことをまとめました。
- もし、書いていることに何か間違いがある場合はご指摘いただけると嬉しいです。
- ここでは、password_hash関数とpassword_verify関数を使ってパスワードのハッシュ化とパスワードの認証をする方法について解説します。

# ハッシュ化とは
- 「ハッシュ化」とは、ハッシュ関数によって文字列を置換して、元の文字を推測できなくすることです。
- 以下の`password`の部分がハッシュ化された値です。
![スクリーンショット 2019-06-02 16.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392565/fd4cc963-c959-0203-4e98-ebc858f5e237.png)

# ハッシュ関数とは
- ハッシュ関数（md5、sha1、sha256、password_hash関数　など）を使うと、特定の決まりに基づいて文字列を置換します。
- ハッシュ化は不可逆変換しているため、一度ハッシュ化すると元に戻すことはできません。


# ハッシュ化をする2つの理由
ハッシュ化をする理由は2つあります。
## 理由1:セキュリティのため
- パスワードを保存したデータベースに悪意のある人から攻撃された場合、パスワード情報が盗まれて悪用されてしまいます。そのため、セキュリティの面でハッシュ化する必要があります。

## 理由2:パスワードをサイトの管理者に知られないようにするため
- サイトの管理者によってもデータベースに保存された情報を悪用されてしまうケースがあります。
- パスワード情報の流出や不正利用を防止するためにハッシュ化する必要があります。

# パスワードをハッシュ化する方法
ここからは、パスワードをハッシュ化する方法について紹介します。
パスワードをハッシュ化するためにpassword_hash関数を使います。
## password_hash関数の書き方

```php
password_hash($password , $algo , $options)
```
## 引数
- `$password`：ハッシュ化したいパスワードの文字列
- `$algo`：アルゴリズムの指定
- `$options`：オプションの指定



# パスワードの認証をする方法
パスワードを認証する方法について紹介します。
パスワードを認証するためにpassword_verify関数を使います。
## password_verify関数の書き方
```php
password_verify ( $password , $hash ) 
```
## 引数
- `$password`：認証したいパスワード
- `$hash`：ハッシュ化されたパスワード


# パスワードのハッシュ化とパスワード認証のコード例

以下のようなデータベースとテーブルがあると仮定して解説します。

**データベース名：** test_db5
**テーブル名：** users

|  email  |  password  |
| ---- | ---- |
|  -  |  -  |

Webサイトで使われている`会員登録機能`と`ログイン機能`を実装することを仮定して解説します。

# 会員登録機能のコード例（password_hash関数）

```php:signup.php
<?php

$user = "ここにユーザー名が入ります";
$password = "ここにパスワードが入ります";

try{

$dbh = new PDO("mysql:host=localhost; dbname=test_db5; charset=utf8", "$user", "$password");

$stmt = $dbh->prepare("INSERT INTO users (email, password) VALUES (:email, :password)");

$stmt->execute(array(':email' => $_POST['email'],':password' => password_hash($_POST['pass'], PASSWORD_DEFAULT)));

}catch(Exception $e){
	echo "データベースの接続に失敗しました：";
	echo $e->getMessage();
	die();
}

?>

<!DOCTYPE html>
<html>
<head>
	<title>会員登録</title>
</head>
<body>
	<h1>会員登録</h1>
	<form action="" method="post">
		<p>
			<label>メールアドレス：</label>
			<input type="text" name="email">
		</p>
		
		<p>
			<label>パスワード：</label>
			<input type="password" name="pass">
		</p>

		<input type="submit" name="submit" value="会員登録する">
	</form>
</body>
</html>

```

## signup.phpの画面
以下の内容を入力して、`会員登録する`ボタンを選択します。

![スクリーンショット 2019-06-02 16.00.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392565/982311ac-2c4d-1680-ebd2-bdb54d0d5afc.png)

### データベースの中身
パスワードがハッシュ化して保存されました。
![スクリーンショット 2019-06-02 16.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392565/0aa0784e-702d-9aa0-20da-1e1f88babb4b.png)

# ログイン機能のコード例（password_verify関数）
```php:login.php
<?php

$user = "ここにユーザー名が入ります";
$password = "ここにパスワードが入ります";

try{
	$dbh = new PDO("mysql:host=localhost; dbname=test_db5; charset=utf8", "$user", "$password");
	
	$stmt = $dbh->prepare('SELECT * FROM users WHERE email = :email');
	
	$stmt->execute(array(':email' => $_POST['email']));

  	$result = $stmt->fetch(PDO::FETCH_ASSOC);
 
  	if(password_verify($_POST['pass'], $result['password'])){
 		echo "ログイン認証に成功しました";
	}else{
		echo "ログイン認証に失敗しました";
	} 

}catch(Exception $e){
	echo "データベースの接続に失敗しました：";
	echo $e->getMessage();
	die();
}

?>

<!DOCTYPE html>
<html>
<head>
	<title>ログイン</title>
</head>
<body>
	<h1>ログイン</h1>
	<form action="" method="post">
		<p>
			<label>メールアドレス：</label>
			<input type="text" name="email">
		</p>
		
		<p>
			<label>パスワード：</label>
			<input type="password" name="pass">
		</p>

		<input type="submit" name="submit" value="ログインする">
	</form>
</body>
</html>

```
パスワード認証に成功すると`ログイン認証に成功しました`と表示され、失敗すると`ログイン認証に失敗しました`と表示されるようにします。


## login.phpの画面
データベースに保存されている情報を入力して、`ログインする`ボタンを選択します。
![スクリーンショット 2019-06-02 16.04.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392565/2e8d3463-6679-c649-f3a8-31f7fb9ab191.png)

### 実行結果
パスワード認証に成功したので`ログイン認証に成功しました`と表示されます。
![スクリーンショット 2019-06-02 16.04.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392565/dbe324a7-2e65-e3d1-abfe-61cf82a25557.png)