Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build and Learn Rails Authentication

sylph01
October 22, 2021

Build and Learn Rails Authentication

@ Kaigi on Rails 2021, 2021/10/22

sylph01

October 22, 2021
Tweet

More Decks by sylph01

Other Decks in Technology

Transcript

  1. 若干真面目な自己紹介 やせいのプログラマ( 要するにフリーランス) W3C, IETF などでセキュリティ寄りのプロトコル の標準化のお手伝いをしていました HTTPS in Local

    Network, Messaging Layer Security など 次世代OAuth の薄い本を書きました 現バージョンは今は頒布中止していますが新 バージョン出したい Kaigi on Rails 1 週間前に松山に引っ越しました
  2. Disclaimer Do try this at home, but Do not try

    this in production できる限り脆弱性を埋め込まないように気をつけて作ることをしますが、通常の場合 production では多数の人によって検証されているライブラリを使用することをおすすめ します。
  3. 認証/ 認可についての概念 人は対象をどのように認知するか? 人/ システムは 対象(Entity) を直接認知しない。 人/ システムは Identity(

    属性の集合) を通して対象(Entity) を認知する。 1 つの対象(Entity) は複数の属性(Identity) を持ち、文脈に応じて使い分ける。
  4. 認証/ 認可についての概念 Authentication( 認証) Entity がサービスの認知するIdentity に紐付いているという確証を得ること 一般にいう「ログイン機能」は、識別子(ID) とパスワードの組を提示できるこ とによって、

    利用するEntity がサービス上のEntity に対応しているという確 証を得られることによって成立する Authorization( 認可) リソースにアクセスするための条件を定めること
  5. 応用 攻撃者が正解のハッシュ値を得られないようにすればよいので、もっとがんばるなら 以下のような方法が取れる: HMAC-SHA256 のsecret を外部のHardware Security Module に保存して、HSM の

    API を通してハッシュ計算をする secret はHSM 上にしかないので、ハッシュ値の計算がHSM にしかできなくな る このような手法をpassword pepper と呼ぶらしい ハッシュ値そのもののアクセスを可能な限りさせないためにデータベース関数を 利用する 後で紹介する rodauth がこの方式を使っている
  6. クッキーからの自動再ログイン?セッションじゃダメ なの? セッション: ブラウザウィンドウが開いている間のみ有効な Cookie のこと セッションはCookie のサブセット Cookie: ここでは「

    ブラウザウィンドウよりも長いライフタイムを持つ Cookie 」 のことを指す 明示的に有効期限を指定したものを指す なのでブラウザウィンドウを閉じた後の再ログインに使える Rails ではセッションは自動で( secret_key_base を使って) 暗号化される Cookie は明示的にsigned かencrypted を指定する必要がある
  7. ワンタイムパスワード HOTP: An HMAC-Based One-Time Password Algorithm (RFC 4226) TOTP:

    Time-Based One-Time Password Algorithm (RFC 6238) を用いるものが一般的。 サーバーと共通の秘密を知っていて、共通の秘密から時刻などに基づいて特定の値を 導出できる という性質をもってEntity が登録ユーザーに対応することを確認してい る。
  8. Devise (1) Warden の上に作られている Warden とは: 認証用 rack middleware session

    middleware の後に入って、session の情報を使って認証状態を確かめ たり認証アクションをトリガーしたりする
  9. 超忙しい人のためのWarden env['warden'].authenticated? - 認証済みであるかを確かめる env['warden'].authenticate(:password) - :password strategy で認証を行う。実際 の認証は各々定義するstrategy

    の中で行う 成功したら env['warden'].user にuser object が入ってくる 認証エラー時は throw(:warden) でWarden の例外を投げる
  10. Devise (2) Devise のstrategy は lib/devise/strategies 以下にある。パスワード認証は DatabaseAuthenticatable strategy で実装されている。

    コントローラーで用いる signed_in? , sign_in , sign_out などは Devise::Controllers::SignInOut で実装されている。Warden の authenticate? や set_user や logout が使われていることがわかる。
  11. Devise (3) Routes に devise_for :users を書くとそのUser が対応しているDevise のモジュール に応じてDevise

    の提供するcontroller へのroute が設定される。 Controller のアクションをカスタマイズしたいときにはDevise の提供するcontroller をそ のまま使いたくない。多分これがDevise を嫌う一番の理由か?
  12. Sorcery code generation を可能な限り使わない、シンプルに切り詰めた認証ライブラリ Devise ではデフォルトから離れたことをしようと思うとコントローラーを継 承したりoverride したりしないといけない Sorcery ではライブラリのメソッドを自分のMVC

    コードの中で使う ただし自己責任の部分が増える 設定はInitializer にまとまっている コード中で sorcery_config を取る動作がよく見られるのはこれ 暗号コードはAuthlogic をベースにしている パスワードの暗号化が可能 at your own risk...
  13. require_login login(email, password, remember_me = false) auto_login(user) logout logged_in? current_user

    redirect_back_or_to @user.external? @user.active_for_authentication? @user.valid_password?('secret') User.authenticates_with_sorcery! (GitHub のreadme より) パスワード認証だけならメソッドは11 個!
  14. UserSession.create(:login => "bjohnson", :password => "my password", :remember_me => true)

    session = UserSession.new(:login => "bjohnson", :password => "my password", :remember_me => true) session.save session = UserSession.find session.destroy (GitHub のreadme より抜粋)
  15. Rodauth (1) "Ruby's most advanced authentication framework" の名に恥じない圧倒的高機能 暗号技術ファンとして素直に感心する WebAuthn

    、ワンタイムパスワード、SMS 、JWT のサポート データベース関数によるパスワードハッシュへのアクセス HMAC を使った"password pepper" の徹底 Rails/ActiveRecord を前提としていない Roda とSequel で作られている がRails での利用方法はそんなに自明ではない
  16. Rodauth (3): password pepper の徹底 hmac_secret を設定することで、以下の値(p.29 で説明した仕組み) の保存時にHMAC が適用される(→

    共通のsecret を使う"password pepper" )。 E メールで送信するtoken remember で使用するtoken ワンタイムパスワードで使用するトークンはユーザーに提示されるキーにHMAC が適 用される。 hmac_secret をメモリ上にのみ存在させることで攻撃者はハッシュ(HMAC) 値の計算 に用いる関数を知ることができない。
  17. おまけ: ハッシュ済みパスワードのカラム名 Devise は encrypted_password 一般にハッシュ化した値をencrypted であるとは言わない Sorcery, Authlogic は

    crypted_password そもそも暗号化済みを指す語は "crypted" ではない Rodauth は password_digest ハッシュ化した値のことを "digest" と呼ぶのは正式な用法 has_secure_password で実装した場合も password_digest
  18. 多分こういう使い分けになる Rails/ActiveRecord に縛られないものが欲しい: Rodauth とにかく普通のパスワード認証+α をさくっと作りたい: Devise 認証周りにたくさんカスタムコードがあって細かく制御したい: Sorcery, Authlogic

    外部認証プロバイダへの移行がありそう: 今のところRodauth 以外 レガシー外部認証方式はAuthlogic に一日の長がある ほぼ初期設定でとにかくセキュアにしたい: Rodauth が有利か? 他がinsecure であるとは言ってないことに注意