こんにちは、
電子書籍を購入しようか検討中のサトウです。
さて、本題に入りたいと思います。
phpの学習を進めると「パスワードをハッシュ化する」という言葉を目にする機会も増えてくるのではないでしょうか。
「ハッシュ化」はセキュリティ上必要でも、考え方や具体的な処理の方法について理解できない方も少なくないのでは、、、。と思い、今回は「ハッシュ化」について分かりやすく説明していきます。
phpを学び始めた方や、「ハッシュ化」について分からない方は、是非読んでみてくださいね。
ハッシュ化の基本
ハッシュ化とは
ハッシュ化とは、複雑なルール(アルゴリズムと言います)によって文字列を置換して、元の文字列を推測できなくすることです。
web開発やアプリケーションでは主にユーザー入力がしたパスワードに対して使われるケースが多いです。
ハッシュ化する理由
ハッシュ化する理由は主に2つあります。
(1)セキュリティ対策のため
パスワードを保存したデータベースに悪意ある攻撃をされた場合、パスワードが漏洩し悪用されてしまいます。そのため、セキュリティの対策としてハッシュ化する必要があります。
(2)パスワードをサービス管理者に知られないようにするため
サービスやwebサイトの管理者によってもデータベースに保存された情報を悪用されてしまうケースがあります。(大規模なシステムやサービスであれば保守・運用の専任担当者がいる場合もあります。)
管理者にパスワード情報の流出や不正利用されないためにもハッシュ化する必要があります。
パスワードをハッシュ化をしてみよう!
phpではハッシュ化する方法はいくつかありますが、以降ではpassword_hash()という関数を使ってパスワードのハッシュ化について解説していきます。
password_hash()の書き方
password_hash()は第2引数にPASSWORD_DEFAULTを指定することで、文字列を変換することができます。
サンプルコード
1 2 3 4 5 6 7 8 9 10 11 |
<?php // 変数にpassword2011と入力 $password = 'password2011'; // ハッシュ化せずに画面表示 echo 'ハッシュ化する前:'.$password.'<br>'; // password_hashでハッシュ化 $password_after = password_hash($password,PASSWORD_DEFAULT); // ハッシュ化したものを表示 echo 'ハッシュ化した後:'.$password_after; |
画面イメージ
password_hash()を使用した後だと文字列が置換されているのが確認できますね。
※今回は記事解説のために上記のコードを書きましたが、パスワードを画面表示するのはセキュリティ上好ましくないので注意してください。
パスワードをハッシュ化してユーザー登録機能を実装してみよう!
ハッシュ化書き方が理解できたところで、ユーザー登録フォームに実装の際にどのように使われるか見ていきましょう。
以下のユーザー登録フォームサンプルを使って解説していきます。
画面イメージ
※入力したパスワードが長い文字列に変換されています。
処理の流れ
(2)postされていれば処理を開始する
(3)postした「名前」と「パスワード」を変数に入れる
(4)例外処理でDB接続準備
(5)PDOオブジェクトでDBに接続
(6)SQL文:usersテーブルにuser_nameとpasswordを挿入する
(7)prepareメソッドを使ってSQL実行準備
(8)executeメソッドでクエリの実行:ハッシュ化したパスワードをDBに登録
サンプルコード(完成)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
<?php // ログの表示 ini_set('log_errors','On'); ini_set('error_log','php.log'); //(2) postされていれば処理を開始する if(!empty($_POST)){ // (3)postした「名前」と「パスワード」を変数に入れる $user_name = !empty($_POST['user_name']) ? $_POST['user_name']:''; $user_pass = !empty($_POST['user_pass']) ? $_POST['user_pass']:''; // (4)例外処理でDB接続準備 // *通常はここでバリデーションチェック* try{ $dsn = 'mysql:dbname=mysql_test3;host=localhost;charset=utf8'; $user = 'root'; $password = パスワード; $options = array( // SQL実行失敗時には例外をスローしてくれる PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // カラム名をキーとする連想配列で取得する.これが一番ポピュラーな設定 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // バッファードクエリを使う(一度に結果セットをすべて取得し、サーバー負荷を軽減) // SELECTで得た結果に対してもrowCountメソッドを使えるようにする PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,); // (5)PDOオブジェクトでDBに接続 $dbh = new PDO($dsn,$user,$password,$options); // (6)SQL文:usersテーブルにuser_nameとpasswordを挿入する // 変数値はそのままセットせず、プレースホルダを使用する $sql = 'INSERT INTO users(user_name ,password,create_date) VALUES(:user_name,:password,:create_date)'; // (7)prepareメソッドを使ってSQL実行準備 $stmt = $dbh->prepare($sql); // (8)executeメソッドでクエリの実行:ハッシュ化したパスワードをDBに登録 $stmt->execute(array( ':user_name' => $user_name, ':password' => password_hash($user_pass,PASSWORD_DEFAULT), ':create_date' => date('Y-m-d H:i:s'))); }catch(Exception $e){ error_log('エラー発生:' . $e->getMessage()); } } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <title>ハッシュ化</title> </head> <body> <section class="contents"> <form action="" method="post" class="form-container"> <!-- (1)formタグからpost送信 --> <label for="" class="label-username">お名前:</label> <input type="text" name="user_name" class="input input-username" placeholder="お名前" > <label for="" class="label-password">パスワード:</label> <input type="password" name="user_pass" class="input input-password" placeholder="パスワード"> <input type="submit" class="btn" value="送信する"> </form> </section> </body> </html> |
formタグからpost送信
formタグから名前(キーをuser_name)とパスワード(キーをuser_pass)をpost送信しています。
サンプルコード(該当箇所)
1 2 3 4 5 6 7 8 9 10 11 |
<form action="" method="post" class="form-container"> <!-- (1)formタグからpost送信 --> <label for="" class="label-username">お名前:</label> <input type="text" name="user_name" class="input input-username" placeholder="お名前" > <label for="" class="label-password">パスワード:</label> <input type="password" name="user_pass" class="input input-password" placeholder="パスワード"> <input type="submit" class="btn" value="送信する"> </form> |
postされていれば処理を開始する
post送信されているかを!emptyで確認しています。
サンプルコード(該当箇所)
1 2 3 4 |
//(2) postされていれば処理を開始する if(!empty($_POST)){ } |
postした「名前」と「パスワード」を変数に入れる
postした内容に情報があればそれを変数に格納しています。
名前情報を$uesr_nameに、パスワード情報を$user_passに格納しています。
サンプルコード(該当箇所)
1 2 3 |
// (3)postした「名前」と「パスワード」を変数に入れる $user_name = !empty($_POST['user_name']) ? $_POST['user_name']:''; $user_pass = !empty($_POST['user_pass']) ? $_POST['user_pass']:''; |
例外処理でDB接続準備
try-catch(例外処理)を書いてデータベース接続の準備をしています。
今回はPDOオブジェクトでDB接続するため、$dsnや$user等引数に必要な情報をそれぞれ格納しています。
サンプルコード(該当箇所)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
(4)例外処理でDB接続準備 try{ $dsn = 'mysql:dbname=mysql_test3;host=localhost;charset=utf8'; $user = 'root'; $password = パスワード; $options = array( // SQL実行失敗時には例外をスローしてくれる PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // カラム名をキーとする連想配列で取得する.これが一番ポピュラーな設定 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // バッファードクエリを使う(一度に結果セットをすべて取得し、サーバー負荷を軽減) // SELECTで得た結果に対してもrowCountメソッドを使えるようにする PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,); }catch(Exception $e){ error_log('エラー発生:' . $e->getMessage()); } |
PDOオブジェクトでDBに接続
この箇所で実際にデータベースに接続します。
サンプルコード(該当箇所)
1 2 |
// (5)PDOオブジェクトでDBに接続 $dbh = new PDO($dsn,$user,$password,$options); |
SQL文:usersテーブルにuser_nameとpasswordを挿入する
今回はテーブルに情報を登録するので、INSERT INTOというSQL文を使用します。
サンプルコード(該当箇所)
1 2 |
// (6)SQL文:usersテーブルにuser_nameとpasswordを挿入する $sql = 'INSERT INTO users(user_name ,password,create_date) VALUES(:user_name,:password,:create_date)'; |
prepareメソッドを使ってSQL実行準備
(6)で使用した情報を引数にしてSQLの実行準備をします。SQLの実行準備にはprepareというメソッドを使用します。
1 2 |
// (7)prepareメソッドを使ってSQL実行準備 $stmt = $dbh->prepare($sql); |
executeメソッドでクエリの実行:ハッシュ化したパスワードをDBに登録
executeメソッドを使用しクエリを実行します。この箇所で変数に入力した情報をデータベースに登録する処理を行います。
パスワードはハッシュ化して登録するためpassword_hash()を使用して、第1引数:$user_name、第2引数:PASSWORD_DEFAULTを指定します。
password_hash($user_pass,PASSWORD_DEFAULT);
サンプルコード(該当箇所)
1 2 3 4 5 |
// (8)executeメソッドでクエリの実行:ハッシュ化したパスワードをDBに登録 $stmt->execute(array( ':user_name' => $user_name, ':password' => password_hash($user_pass,PASSWORD_DEFAULT), ':create_date' => date('Y-m-d H:i:s'))); |
まとめ
いかがでしたか?今回は、ハッシュ化について説明しました。
プログラミングを学び始めた頃は、「パスワードのハッシュ化」について難しく感じることあると思います。ですが、まずはシンプルなユーザー登録機能から実装していけば、簡単に使えることができる日が来ると思うので、焦らずにゆっくりと理解を深めていってくださいね
この記事が、phpの学習に役立つと嬉しいです。