Rails の devise でログインを判定する仕組み

rails

devise 使ってると user_signed_in? とか current_user とか使いますよね?

ブラウザはどのように、現在ログイン中かどうかを認識しているのでしょうか?

解析してみました。

クッキー解析

秘密はクッキーにあります。

以下の手順で、rails でログインしている場合としてない場合でクッキーの違いを見てみましょう。

Chrome でクッキーを確認する方法
https://nomad.office-aship.info/chrome-cookie

以下のように _test_rails_session という項目があります。

これが、ログインを保持している値です。

試しにこの _test_rails_session を削除してリロードすると、ログアウト扱いになります。

このプロジェクトは test_rails というrailsプロジェクト名なので、

名前は _#{railsプロジェクト名}_session という名前になっているようです。

ちなみに、この Value、リロードするたびに変化します。

Qi53lK28PWdWi%2BdR8SVvFnBUGGUV8cKIyFCEP9EkPtIC%2B%2BNO86CYvJ1ALTFaK4MG7iPLXddBweG5qyiCNToHDF1V%2BMF1hZUR%2F4%2BIjJP4BsXSJlFuC2A2Y8jnhmnhpJLjY5NgFjMK7lRhN28wNiTxhrEvJGh1pU5PtivUogd3ik5f2zMZXxWdJ2Zb9WYXFRA43WKqe0g%2B71Yx9QJMRV0wLc00fXpMlmDliR19em%2Bh2wBBfNF%2Buw3j8F9lxVBMqvN55S3NHdQM1Oi8FoQWy5MKXeoFIGccM%2FlJ8LgaZuaYEHWDU%2BGzc4SKVsLqxgi2nteIljbV1fLbN4%2BOpTk2yn5aa0%2BuLLmztBTgOcbA5wufXfy0eFOkqwF%2BdkeZ5GAXKF6UjtkC8ta82aYslNt76MiU%2FrzvuraiU3w%3D–R3iubSvMRrdv6uDT–lu94yoOUEN7cLqYHW6Y1IA%3D%3D

このキーを復号してみます。

以下に掲載のコードで復号できました(rails 6.1.4 で確認済み)

Demystifying cookies in Rails 6 – 2020.11/2
https://binarysolo.chapter24.blog/demystifying-cookies-in-rails-6

以下のファイルを置いて
以下のように実行できます。
ファイル中の cookie の値は、自分の値に書き換えてください。
この時、 Show URL decoded のチェックボックスはオフにしてください。

% bundle exec rails cookie:decode_cookie
{"session_id"=>"7bc124c13de60bdc12d810b69aff8ed2", "warden.user.user.key"=>[[2], "$2a$12$lJTRmJqKO3u9iSI28S/6W."], "flash"=>{"discard"=>[], "flashes"=>{"notice"=>"Signed in successfully."}}}

lib/tasks/decode_cookie.rake

# frozen_string_literal: true

namespace :cookie do
  # % bundle exec rails cookie:decode_cookie 
  # 本番では RAILS_ENV=production をつける
  task decode_cookie: :environment do
    # Take the following value from your cookie for your web site
    cookie = 'Qi53lK28PWdWi%2BdR8SVvFnBUGGUV8cKIyFCEP9EkPtIC%2B%2BNO86CYvJ1ALTFaK4MG7iPLXddBweG5qyiCNToHDF1V%2BMF1hZUR%2F4%2BIjJP4BsXSJlFuC2A2Y8jnhmnhpJLjY5NgFjMK7lRhN28wNiTxhrEvJGh1pU5PtivUogd3ik5f2zMZXxWdJ2Zb9WYXFRA43WKqe0g%2B71Yx9QJMRV0wLc00fXpMlmDliR19em%2Bh2wBBfNF%2Buw3j8F9lxVBMqvN55S3NHdQM1Oi8FoQWy5MKXeoFIGccM%2FlJ8LgaZuaYEHWDU%2BGzc4SKVsLqxgi2nteIljbV1fLbN4%2BOpTk2yn5aa0%2BuLLmztBTgOcbA5wufXfy0eFOkqwF%2BdkeZ5GAXKF6UjtkC8ta82aYslNt76MiU%2FrzvuraiU3w%3D--R3iubSvMRrdv6uDT--lu94yoOUEN7cLqYHW6Y1IA%3D%3D'
    secret_key_base = Rails.application.secret_key_base

    puts decrypt_session_cookie(cookie, secret_key_base)
  end

  private
  def decrypt_session_cookie(cookie, secret_key_base)
    unescaped_cookie = CGI::unescape(cookie)

    data, iv, auth_tag = unescaped_cookie.split("--").map do |v| 
      Base64.strict_decode64(v)
    end

    cipher = OpenSSL::Cipher.new("aes-256-gcm")

    # Compute the encryption key
    secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret_key_base, "authenticated encrypted cookie", 1000, cipher.key_len)

    # Setup cipher for decryption and add inputs
    cipher.decrypt
    cipher.key = secret
    cipher.iv  = iv
    cipher.auth_tag = auth_tag
    cipher.auth_data = ""

    # Perform decryption
    cookie_payload = cipher.update(data)
    cookie_payload << cipher.final
    cookie_payload = JSON.parse cookie_payload
    # => {"_rails"=>{"message"=>"InRva2VuIg==", "exp"=>nil, "pur"=>"cookie.remember_token"}}

    # Decode Base64 encoded stored data
    decoded_stored_value = Base64.decode64 cookie_payload["_rails"]["message"]
    stored_value = JSON.parse decoded_stored_value
    # => "token"
  end
end

では、この value の値は、どのように生成されているのでしょうか?

[Rails] deviseのセッション(session)はどのように決められているのか
https://qiita.com/eitches/items/aefa728148cba68f2d6a

Rails6 のセッションの扱いと、クッキーからの復元方法
https://tyfkda.github.io/blog/2020/09/01/rails6-session-cookie.html

wildjcrt/verify_and_decrypt_session_cookie60beta1.rb
https://gist.github.com/wildjcrt/6359713fa770d277927051fdeb30ebbf

pdfrod/decode_session_cookie.rb
https://gist.github.com/pdfrod/9c3b6b6f9aa1dc4726a5

Rails の session を完全に理解した – 2019年07月16日
https://qiita.com/zettaittenani/items/a75f0da8f44cfe0f85c0

ruby-on-rails – Rails 4:Rails 4セッションCookieを復号化する方法(セッションキーとシークレットを指定)
https://base64.work/so/ruby-on-rails/1580567

Rails 3はcookieはbase64デコードで簡単にデコードできる。
Rails 4以降は、AES-256を使用して、アプリのsecret_token_baseに基づくキーでCookieを暗号化します。

How to decode and decrypt cookies in Rails 6
https://www.indiehackers.com/post/how-to-decode-and-decrypt-cookies-in-rails-6-41c420f378

Rails の cookie session をデコードする – 2017-02-25
https://ohbarye.hatenablog.jp/entry/2017/02/25/144008

How to decrypt a Rails 5 session cookie manually?
https://stackoverflow.com/questions/41474176/how-to-decrypt-a-rails-5-session-cookie-manually

Gist

てか、Gist って何ですかね?

Gistとはコード断片の共有サービス。

Github Gistの良いところ、悪いところ
https://qiita.com/YumaInaura/items/d8ba7ce702d844f11ae0

コメント

タイトルとURLをコピーしました