Rails 7: has_secure_password
利用時のauthenticate_by
メソッド(翻訳)
急速に成長するデジタル世界で誰もが気がかりなものといえば、セキュリティです。
フィッシングや違法行為がしばしば発生する今日のサイバーエコシステムでは、セキュリティの必要性は避けては通れません。
認証(authentication)は、多くのWebサイトがセキュリティ実現のために採用している基本的なしくみです。認証を手短に説明すると、ユーザー(顧客)がWebサイトのさまざまなコンテンツにアクセスするときに、「ユーザー名(またはメールアドレス)」「パスワード」でログインすることを要求するというものです。
改修前
たとえばCustomer
モデルにemail
属性があるとします。ここに"richard_roe@example.com"
というメールアドレスを持つレコードが1件あります。このcustomerレコードは以下のように作成できます。
Customer.create(name: "Richard Roe", email: "richard_roe@example.com", password: "password123")
注意: 以下のコードスニペットはcustomerの認証に使われます。このコードは、マッチするメールアドレスがcustomerに存在しない場合は早期に早めに処理が終了します。return
します
Customer.find_by(email: "richard_roe@example.com")&.authenticate("password123")
上のコードスニペットは、指定のメールアドレスを持つcustomerが存在するかどうかを攻撃者が判断できてしまうため、タイミングベースの列挙攻撃に対して脆弱です。
専用のパスワード管理アプリケーションを使わず、同じパスワードを複数のWebサイトで使いまわしてしまう人は跡を絶ちません。
攻撃者はデータベースにアカウントが存在することを確認すると、インターネット上に流出したデータベースの中から該当するメールアドレスのパスワードを探してログインを試みます。アカウントのメールアドレスが事前にわかっている場合、攻撃者は標的を絞り込んだブルートフォース攻撃やフィッシング(スピアフィッシング)攻撃も試せます。
改修後
Rails でauthenticate_by
というクラスメソッドが新たに導入されます。
Customer.authenticate_by(email: "richard_roe@example.com", password: "password123")
authenticate_by
は、指定のパスワード属性をダイジェスト化し、タイミングベースの列挙攻撃を軽減するのに役立ちます。このメソッドは、パスワード以外の属性を利用してレコードを検索し、見つかったレコードをパスワード属性で認証します。
認証が成功した場合はそのレコードを返し、失敗した場合はnil
を返します。
class Customer < ActiveRecord::Base
has_secure_password
end
Customer.create(name: "Richard Roe", email: "richard_roe@example.com", password: "password123")
Customer.authenticate_by(email: "richard_roe@example.com", password: "password123").name
# => "Richard Roe"
Customer.authenticate_by(email: "richard_roe@example.com", password: "invalid_password")
# => nil
Customer.authenticate_by(email: "invalid@example.com", password: "password123")
# => nil
このメソッドは、属性のセットに少なくとも1個のパスワード属性と1個の非パスワード属性が含まれている必要があります。それらの属性がない場合はArgumentError`エラーが発生します。
Customer.authenticate_by(email: "richard_roe@example.com")
# => ArgumentError
Customer.authenticate_by(password: "password123")
# => ArgumentError
変更内容について詳しくは、#43765(および#43779、#43958、#43997)をご覧ください。
概要
元サイトの許諾を得て翻訳・公開いたします。
authenticate_by
method when usinghas_secure_password
| Saeloun Blog注: この#43765はRailsのmainブランチにマージされていますが、現時点ではまだ7-0-stableブランチに含まれていません。
authenticate_by
追記(2023/09/26): #43765はその後7-0-stableブランチには含まれず、7.1.0beta1で初めて含まれました。また、パスワードが空の場合の修正も7.1.0beta1に含まれました。
authenticate_by
on empty password by jonathanhefner · Pull Request #43958 · rails/rails