セキュアなパスワードを追加する
ユーザー属性の「名前」と「メールアドレス」に対してバリデーションを追加したので、最後に「セキュアなパスワード」に取り掛かります。セキュアパスワードという手法では、各ユーザーにパスワードとパスワードの確認を入力させ、それをハッシュ化したものをデータベースに保存します。
いきなりハッシュ化と言われると少し困惑してしまうかもしれません。
ハッシュとはRubyのデータ構造であると説明しましたが、今回の「ハッシュ化」とはそういった構造ではなく、ハッシュ関数を使って、入力されたデータを元に戻せない(不可逆な)データにする処理を指します。
ユーザーの認証は、パスワードの送信、ハッシュ化、データベース内のハッシュ化された値との比較、という手順で進んでいきます。
比較の結果が一致すれば、送信されたパスワードは正しいと認識され、そのユーザーは認証されます。
ここで、生のパスワードではなく、ハッシュ化されたパスワード同士を比較していることに注目してください。
こうすることで、生のパスワードをデータベースに保存するという危険なことをしなくてもユーザーを認証できます。
これで、仮にデータベースの内容が盗まれたり覗き見されるようなことがあっても、パスワードの安全性が保たれます。
ハッシュ化されたパスワード
セキュアなパスワードの実装は、has_secure_passwordというRailsのメソッドを呼び出すだけでほとんど終わってしまいます。
このメソッドは、Userモデルで次のように呼び出せます。
class User < ApplicationRecord
.
.
.
has_secure_password
end
上のようにモデルにこのメソッドを追加すると、次のような機能が使えるようになります。
セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。
2つのペアの仮想的な属性(passwordとpassword_confirmation)が使えるようになる。
また、存在性と値が一致するかどうかのバリデーションも追加される。
authenticateメソッドが使えるようになる(引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド)。
この魔術的なhas_secure_password機能を使えるようにするには、1つだけ条件があります。
それは、モデル内にpassword_digestという属性が含まれていることです。
ちなみにdigestという言葉は、暗号化用ハッシュ関数という用語が語源です。
したがって、今回の用途ではハッシュ化されたパスワードと暗号化されたパスワードは類義語となります。
今回はUserモデルで使うので、Userのデータモデルは次の図のようになります。
データモデルにするために、まずはpassword_digestカラム用の適切なマイグレーションを生成します。
マイグレーション名は自由に指定できますが、次に示すように、末尾をto_usersにしておくことをオススメします。
こうしておくと、usersテーブルにカラムを追加するマイグレーションがRailsによって自動的に作成されるからです。add_password_digest_to_usersというマイグレーションファイルを生成するためには、次のコマンドを実行します。
$ rails generate migration add_password_digest_to_users password_digest:string
# テーブルにカラムを与えるために引数にカラムとそのデータ型をしている
上のコマンドではpassword_digest:stringという引数を与えて、今回必要になる属性名と型情報を渡しています。
usersテーブルを最初に生成するとき、name:stringやemail:stringといった引数を与えていたことを思い出してください。
そのときと同様にpassword_digest:stringという引数を与えることで、完全なマイグレーションを生成するための十分な情報をRailsに与えることができます(リスト 6.36)。
cclass AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :password_digest, :string
# genalateによって生成された絡むとそのデータ型
# 追加されたカラム
end
end
リスト 6.36では、add_columnメソッドを使ってusersテーブルpassword_digestカラムを追加しています。
これを適用させるには、``データベースでマイグレーション```を実行します。
ubuntu:~/environment/sample_app (modeling-users) $ rails db:migrate
== 20210926142302 AddPasswordDigestToUsers: migrating =========================
-- add_column(:users, :password_digest, :string)
-> 0.0138s
== 20210926142302 AddPasswordDigestToUsers: migrated (0.0145s) ================
また、has_secure_passwordを使ってパスワードをハッシュ化するためには、最先端のハッシュ関数であるbcryptが必要になります。
パスワードを適切にハッシュ化することで、たとえ攻撃者によってデータベースからパスワードが漏れてしまった場合でも、Webサイトにログインされないようにできます。
サンプルアプリケーションでbcryptを使うために、bcrypt gemをGemfileに追加します。
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '6.0.3'
gem 'bcrypt', '3.1.13'
gem 'bootstrap-sass', '3.4.1'
.
.
.
$ bundle install
Gemfileを編集したら実行する