Rails の CookieStore をデコード

いやー、意外と苦労しました。

第一稿は、オブジェクトが初期化出来なかったので破棄し、
第二稿は、初期化に必要な情報が直書きだったので書き直し、
これが第三稿です。

secret = ActiveSupport::CachingKeyGenerator.new Rails.application.key_generator
encryptor = ActiveSupport::MessageEncryptor.new secret.generate_key(Rails.application.config.action_dispatch.encrypted_cookie_salt),
                                                secret.generate_key(Rails.application.config.action_dispatch.encrypted_signed_cookie_salt),
                                                serializer: ActionDispatch::Cookies::NullSerializer
encryptor.decrypt_and_verify CGI.unescape(cookie_str)

 業務でクッキーストアの情報を知る必要が出てきたので、デコード方法を探したのですが…
 どれもうまくいきませんでした。

 情報が古かったのか、何なのか、原因は不明ですが、とにかく急ぎで対応する必要があったのでgem内を色々漁ってなんとかしてみました。

 ちなみに業務での Rails のバージョンは 4.1.8 です。

 クッキーストアの値はCookieのRails.application.config.session_options[:key]で取得できるキーにエンコードされて格納されており、こいつをデコードする必要があります。
 デコードは ActiveSupport::MessageEncryptor オブジェクトの decrypt_and_verify メソッドでできるのですが、初期化するためにはシリアライザークラスと、encrypted_cookie_salt と encrypted_signed_cookie_salt を元に作られた key が必要になるので、まずはキーを作りたいのですがそれには ActiveSupport::CachingKeyGenerator オブジェクトが必要で、これの初期化には ActiveSupport::KeyGenerator が必要です。
 さらに ActiveSupport::KeyGenerator の初期化には secret キーと iterations の値が必要ということがわかりました。

 整理すると、下記クラスの初期化が必要です。

  1. ActiveSupport::KeyGenerator
  2. ActiveSupport::CachingKeyGenerator
  3. ActiveSupport::MessageEncryptor

 初期化のためには下記の情報が必要です。

  1. secret キー
  2. iterations
  3. encrypted_cookie_salt
  4. encrypted_signed_cookie_salt
  5. シリアライザークラス

 情報が多くて面倒ですが、一つ一つ順を追って確認していきます

secret キー

 Rails.application.secrets[:secret_key_base] で取得可能であることが判明。
 (設定されている値は /config/secrets.yml の該当する環境の値)

iterations

 iterations の値がどうやっても見つからない。
 設定しないで ActiveSupport::KeyGenerator を初期化することも可能だったが、それだと iterations の値が 65536 に指定されてしまう。
 ”何故か” Rails デフォルトだと、iterations の値は1000になっているので、なんとかしてこの設定値を探しだそうと躍起になった結果…

 Rails.application.key_generator に初期化済みのオブジェクトを見つけましたっ!
 この初期化済みのオブジェクトを作成するときに 1000 の値を使っていて、クッキーストアの値をエンコードする時にはこのオブジェクトを使っているようです。

ActiveSupport::KeyGenerator オブジェクト

 上記記載の通り Rails.application.key_generator に初期化済みのオブジェクトが有るためこれをそのまま使います。
 …何のために secret キーとか調べたのか。

encrypted_cookie_salt

 デフォルト値だと encrypted cookie になっているようですが、これの設定はどこに有るんだろうと探したところ、…/lib/action_dispatch/railtie.rb (ver.4.1.8) に記述が有りました。
 ここには config.action_dispatch.encrypted_cookie_salt = ‘encrypted cookie’ とあったので Rails.application.config.action_dispatch.encrypted_cookie_salt で取れるみたいです。

encrypted_signed_cookie_salt

 encrypted_cookie_salt と同じ所に有りました。
 ちなみにデフォルト値は signed encrypted cookie です

シリアライザークラス

 これの指定はクッキーストアに値を格納するために使われている ActionDispatch::Cookies::EncryptedCookieJar クラスのコンストラクタに記載がありました。
 具体的には …/lib/action_dispatch/middleware/cookies.rb (ver.4.1.8) の 511 行目にあります。

        secret = key_generator.generate_key(@options[:encrypted_cookie_salt])
        sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
        @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: NullSerializer)
      end

      def [](name)

 ココで ActionDispatch::Cookies::NullSerializer を直値で渡しているため、もうこれは直書きです。

ActiveSupport::MessageEncryptor

 ActiveSupport::MessageEncryptor に encrypted_cookie_salt と encrypted_signed_cookie_salt と シリアライザークラス を渡して初期化すればOKです。

最後に

 クッキーストアの値は HTML エンコードされているので CGI.unescape メソッド使ってデコードするのを忘れないようにしてください。
 僕は忘れて2時間ぐらいハマってました…

RSS / feedly
  • follow us in feedly
  • follow us in feedly
ソーシャル
広告