定期的にDevise批判の話が出てくるので、個人的な考えを書いてみます。
Railsに詳しくないなら、Deviseを使わないべきか?
「認証自作、 Rails 、 Devise」の記事で以下のような記載がある。
「Rails について深い理解がないならば、 Devise は使うな」とあります。この方針は10 年近く前から書かれています。
これ元の英語とあってない気がするんですよね。
If you are building your first Rails application, we recommend you do not use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch. Here's a few resources that should help you get started: - Michael Hartl's online book: https://www.railstutorial.org/book/modeling_users - Ryan Bates' Railscasts: http://railscasts.com/episodes/250-authentication-from-scratch and http://railscasts.com/episodes/250-authentication-from-scratch-revised - Codecademy's Ruby on Rails: Authentication and Authorization: https://www.codecademy.com/learn/rails-auth Once you have solidified your understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. 😃
私には「最初のRailsアプリではDeviseを使わず、シンプルな認証機能を自作して理解を深めるのを勧める」「Railsと認証メカニズムの理解を深めたら、Deviseが快適に動くのが分かるよ」くらいの内容に読めました。1
IPアドレスが漏れる危険性がある?
試してみた。
require "devise/version" Devise::VERSION #=> "4.7.2" user = User.create(email: 'a@example.com', password: 'password') user.to_json #=> => "{\"id\":1,\"email\":\"a@example.com\",\"created_at\":\"2020-08-16T08:31:36.558Z\",\"updated_at\":\"2020-08-16T08:31:36.558Z\"}" user.attributes.to_json #=> "{\"id\":1,\"email\":\"a@example.com\",\"encrypted_password\":\"$2a$12$ECNX7kXJQKMSBp8xDcy5neVs/2NeuTdcqVnPyUbcy8fp.p4EWfBa6\",\"reset_password_token\":null,\"reset_password_sent_at\":null,\"remember_created_at\":null,\"sign_in_count\":0,\"current_sign_in_at\":null,\"last_sign_in_at\":null,\"current_sign_in_ip\":null,\"last_sign_in_ip\":null,\"confirmation_token\":null,\"confirmed_at\":null,\"confirmation_sent_at\":null,\"unconfirmed_email\":null,\"failed_attempts\":0,\"unlock_token\":null,\"locked_at\":null,\"created_at\":\"2020-08-16T08:31:36.558Z\",\"updated_at\":\"2020-08-16T08:31:36.558Z\"}"
attributesメソッドには全属性が含まれちゃうので、漏れる可能性はありそう。
ただ、これDeviseの問題なのかな...。
IPアドレスがDBに保存されている場合2、認証を自作してたとしても実装ミスると漏れるときは漏れると思うんですよね。
テストコードで防ぐ
Twitterやはてブで「レビューで防ぐべき」とかあったけど、レビューのような人依存な対策だと漏れがあるので、テストコード書くのが良いかなと思いました。
# spec/rails_helper.rb RSpec.configure do |config| # html/jsonに含まれてたらヤバそうな文字列を列挙しておく secrets = %w[password lastSignInIp] config.after(type: :request) do |ex| secrets.each { |secret| expect(response.body).not_to include(secret) } end config.after(type: :system) do |ex| secrets.each { |secret| expect(page.body).not_to include(secret) } end end
カバレッジがある程度高ければ、上のコードでだいたい防げるんじゃないかなと。
機能が少ないので自作の方がメンテしやすい?
個人的な経験ですが、認証機能が少ないままで済んだ事がないです。
のような要望が後から出ることが多い。
特に認証機能はプロジェクト初期に作られるためテストコードが不足していたり、誰も壊したくないので条件分岐が雑に増えていってAbcSizeが高くなる状況が生まれやすいです。
個人的な見解
認証機能を自作する自信がないなら、最初からDeviseを使っておくのが無難じゃないかなーと思ってます。
Deviseのコード読んだ上で認証機能を自作できるレベルの人ならまだしも、「Devise使うのは危ないようなので自作しました!」とかのレベルの人は大人しくDevise使っておけと思う。
— 神速 (@sinsoku_listy) 2020年8月16日
お金あるなら Deviseを使い慣れているフリーランス や 技術顧問 してる人と短期の契約をして、相談するのも良いと思います。
認証機能を自作するなら
少なくとも以下の調査はしておいた方が良いです。
- Deviseのコード内にあるセキュリティ対策のコメントを調査する
- timing attacks, session fixation attacks, ...etc
- Deviseのリダイレクト関連の挙動を調査する
- (認証が必要な)ページA => ログイン => ページA の画面遷移の処理
- パスワードリセットのURLを踏んだときのリダイレクト先3
- Deviseのテストヘルパーの挙動を調査する
- Deviseのモジュールと同じ要件がきた時のことを考慮する
- アカウントロックとか後から出てきがち
- 他gemが提供するDevise連携を使えない事を理解する
Deviseにあるような機能は将来に必要になる可能性が高いので、ある程度は考慮しておいた方が良いです。
あと、Deviseを避けて認証機能を自作した結果、Deviseが何年も前に対応済みの脆弱性を再実装するのは勿体ないです。
まとめ
Deviseが最高の認証ライブラリとは思ってないけど、十分に便利なライブラリだとは思ってます。
認証機能のセキュリティをちゃんと考えて実装できる人はさておき、Rails初心者〜中級者ならDeviseを使うでも良いのかなと。