(付録)パスワードのハッシュ化について
現在の課題リポジトリのECサイトアプリについてはパスワードのハッシュ化が行われておりません。
今回の課題には含まれていませんが、実際のアプリケーションではセキュリティ上パスワードのハッシュ化が必須となります。
この付録では、基本的なパスワードのハッシュ化について解説します。
ハッシュ化とは
ハッシュ化とは、元データをハッシュ関数と呼ばれるものを利用して変換することです。
ハッシュ関数の特徴として、
- 元データが同じならば変換後は必ず同じ値になる
- 変換後の値から元データの値を復元することが不可能である
といったものがあります。パスワードのハッシュ化においては、ハッシュ関数の上記二つの特性を活用して処理を行います。
パスワードのハッシュ化を行わないことの問題点
現在の課題リポジトリのECサイトアプリケーションでは、パスワードのハッシュ化を行っていません。
これは「何らかの手段でDBのユーザーデータが覗き見られたら、パスワードが漏洩する」ということを意味します。また、DBのユーザーテーブルを扱う人間は全員パスワードを把握できることにもなります。
上記のリスクを避けるため、パスワードのハッシュ化が必要となります。
パスワードのハッシュ化とは
パスワードのハッシュ化とは、パスワードそのものではなく、パスワードをハッシュ化した後の値を保存して、ログイン認証などに用いることです。
- 元データが同じならば変換後は必ず同じ値になる
という特徴があるため、
登録時に保管したパスワードのハッシュ値が、ログイン認証時に入力されたパスワードのハッシュ値と一致していれば、パスワードが一致したとみなすことが可能です。
そして、
- 変換後の値から元データの値を復元することが不可能である
という特徴があるため、DBに保存されているパスワードのハッシュ値が漏洩したとしても、ログインフォームに入力すべきパスワードを推測することができません。
ハッシュ化の実装
PHPでは、password_hash関数を用いることで、パスワードのハッシュ化が可能です。
$hash = password_hash($password, PASSWORD_DEFAULT);
上記の$hashをDBに保存することで、ハッシュ化されたパスワードを保存することが可能です。
ハッシュ化されたパスワードの照合
PHPでは、password_verify関数を用いることで、password_hash関数でハッシュ化されたパスワードの照合が可能です。
if($user === false || password_verify($password, $user['password']) === false){
return false;
}
例えば上記の様なコードでハッシュ化されたパスワードの照合が可能です。
既存ユーザーパスワードのハッシュ化
パスワードのハッシュ化を実装する場合、既存ユーザーのパスワードについてもハッシュ化しておく必要があります。
例えば、adminユーザーのパスワード「admin」のハッシュ値を確認したい場合には、
dd(password_hash('admin', PASSWORD_DEFAULT));
上記のコードを実行することで簡単に確認できます。 登録されている既存ユーザー数が少ない場合には、上記のコードを各ユーザーに対して実行した上で、phpmyadminから各既存ユーザーのパスワードを更新しておくと良いでしょう。
ハッシュ化と暗号化の違い
上記の処理を「パスワードの暗号化」と解説されているケースがありますが、パスワードのハッシュ化と暗号化は異なります。
暗号化とは、暗号化されたデータから元のデータが復元可能な変換です。復元ができないハッシュ化とは明確に異なります。
解説の様に、パスワードについてはハッシュ化の「復元ができない」という性質を活用しているため、しっかり区別しておくと良いでしょう。
現在は利用できないハッシュ関数について
以前は有効であったハッシュ関数が現在では利用できないケースもあります。有名なものではmd5やsha1というハッシュ関数では、同じハッシュ値を生成する2つ以上のデータを生成することが現実的に可能になっています。(ハッシュ値の衝突)
ハッシュ値の衝突が可能であるからといって、すぐにパスワードのセキュリティが破られてしまうわけではありませんが、潜在的なリスクとなるため、現在ではセキュリティに用いるハッシュ化のアルゴリズムとしてはmd5やsha1は使用を控えられています。(単にランダムな文字列を取得したいなどの理由の場合には利用しても問題ありません。)
辞書攻撃について
ハッシュ化の仕組みの弱点として、よく使われる単語(辞書に載っている単語)とハッシュ値の対応表を作成しておけば、ハッシュ化した値から対応する元の単語を見つけ出されてしまうというものがあります。
ソルトなど、この攻撃を防ぐ仕組みもありますが、それらを考慮に入れても、セキュリティを高めるためには辞書に存在しない文字の組み合わせをパスワードとして利用することが望ましいとされています。