概要
パスワードをデータベースに保存する際に暗号化して、万一流出した際のリスクを減らす方法。ここではハッシュ化してメッセージダイジェストにすることを「暗号化」とする。
暗号化されたパスワードを保存しておき、サインインの際に入力されたパスワードを同じ手順で暗号化し、得られたメッセージダイジェストが一致すれば符合しているとする。
以下の方法で順次リスクを減らしていく。
- パスワードをハッシュ化
- パスワードにソルトを連結してハッシュ化
- パスワードとソルトをそれぞれハッシュ化したものを連結してハッシュ化
- より安全性の高いハッシュ化を適用
ここでは3つ目の方法でRailsのDigest::MD5を使った手順を整理。
手順
パスワードを与える。
password = "pass"
ソルトを準備する。
salt = "SdvLigVDW3iDtHGAYvccBSbDn+jl"
パスワードとソルトを連結した文字列を暗号化する。
Digest::MD5.hexdigest(pass_digest + salt_digest)
この結果、以下のメッセージダイジェストが得られる。
"d1d7bd4a8d1e0a3be09d701db50ec038"
パスワードをpass→sassにしたときのメッセージダイジェストは以下の通り。
"82035cbcc496621133b8773709285313"
モデルへの実装
Railsでモデルを介してデータベースに登録する場合、モデルに暗号化の処理を書く。たとえばUserモデルのpasswordを暗号化する場合の例は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class User < ApplicationRecord before_create :encrypt_password def encrypt_password self.password = User.password_digest(password) end def self.password_digest(password) salt = "Qc7XGCLIRTzAG7r3Wo7H7Ui++jr0" pass_digest = Digest::MD5.hexdigest(password) salt_digest = Digest::MD5.hexdigest(salt) Digest::MD5.hexdigest(pass_digest + salt_digest) end end |
before_create
でコールバックを設定していて、データベースへの書き込み前にencrypt_password
メソッドが呼ばれる。
これをbefore_saveで呼ぶとデータ更新のときにもパスワードがハッシュ化されてしまうので、データの新規作成のときだけ呼ばれるようbefore_create
で呼ばなければんならない。
encrypt_password
はクラスメソッドのpassword_digest
でpassword
をメッセージダイジェストに変換し、その値でpassword
を書き換える。
password_digest
メソッドは、パスワードとソルトからメッセージダイジェストを返す。
その結果、データベースへの書き込み時には暗号化されたパスワードが保存される。