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

今さら聞けないセッションとCookie、ログイン・ログアウト(Rails編) – 2016年1月7日
https://qiita.com/SpicyCoffee/items/de9de9a5427adf81817a

Rails API(サーバサイド)でCookieを作成する方法 – 2022年2月7日
https://nishinatoshiharu.com/rails-serverside-cookies

セッションとかクッキーとかよくわからないので勉強してみた – 2021年6月7日
https://qiita.com/hot_study_man/items/147f8b767b4135fe6fe4

[Rails]sessionとcookies。得意になりたくない? – 2021年04月17日
https://qiita.com/ren0826jam/items/a0d2eb76b4c571a02c2b

Ruby on Rails チュートリアル 第9章 永続的セッション
(cookies remember me 記憶トークン ハッシュ)を解説 – 2021年1月27日
https://qiita.com/bitcoinjpnnet/items/639cbace7cb806379452

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

RSpec書籍

Everyday Rails – RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp

Rails 7.0に対応した「Everyday Rails – RSpecによるRailsテスト入門」をリリースしました! – 2022-01-17
https://blog.jnito.com/entry/2022/01/17/115109

おすすめRuby書籍

研鑽Rubyプログラミング β版
https://www.lambdanote.com/products/products-polished-ruby-beta

プロを目指す人のためのRuby入門[改訂2版] – 2021/12/2

Ruby on Rails 6 実践ガイド impress top gearシリーズ

現場で使える Ruby on Rails 5速習実践ガイド

Ruby on Rails 6 超入門

コメント

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