##セキュアなパスワードを追加する
ユーザー属性の「名前」と「メールアドレス」に対してバリデーションを追加したので、最後に「セキュアなパスワード
」に取り掛かります。セキュアパスワードという手法では、各ユーザーにパスワードとパスワードの確認を入力させ、それをハッシュ化
したものをデータベースに保存します。
いきなりハッシュ化と言われると少し困惑してしまうかもしれません。
ハッシュとは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を編集したら実行する