はじめに
こんにちは、onoです。
現在開発中のアプリケーションでログインAPIのテストコードを実行したところ、
Ruby2.3.1ではうまくいっていたCookieの復号が、Ruby2.4.1ではエラーが発生したので調査しました。
前提条件
Ruby 2.4.1
Rails 5.1.0
発生したエラー
実際のコード
実際のコードは下記の通りです。
1 2 3 4 5 6 7 | # cookieの複合処理 unescaped_content = CGI.unescape(response.cookies['_app-server_session']) secret = Rails.application.key_generator.generate_key('encrypted cookie') sign_secret = Rails.application.key_generator.generate_key('signed encrypted cookie') encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) decrypted_hash = encryptor.decrypt_and_verify(unescaped_content).with_indifferent_access user_by_cookie = User.find(decrypted_hash[:user_id]) |
Ruby 2.3.1で開発していた前のアプリケーションでは、上記のコードで復号できていました。
ところが、Ruby 2.4.1で開発中のアプリケーションではエラーが発生しました。
エラー詳細
6行目の encryptor.decrypt_and_verify の箇所で下記のエラーが発生しました。
1 | ArgumentError: key must be 32 bytes |
原因
どうやら、Rubyの openssl が変更になったために発生したようです。
今までは、keyに長すぎる値を渡すと自動的に適当な長さに切り取っていたようですが、正しい長さのkeyを渡さないと例外が発生するようになりました。
参考:http://nisshiee.hatenablog.jp/entry/2017/04/17/192703
どう対処したか
修正後のコード
修正前は64byteのkeyが生成されていましたが、ActiveSupport::KeyGeneratorでkeyを生成するようにしたところ、エラーが解消されました。
1 2 3 4 5 6 7 8 9 10 11 | def verify_and_decrypt_session_cookie(cookie) secret_key_base = Rails.application.secrets[:secret_key_base] cookie = CGI::unescape(cookie) salt = 'encrypted cookie' signed_salt = 'signed encrypted cookie' key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000) secret = key_generator.generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len] sign_secret = key_generator.generate_key(signed_salt) encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) encryptor.decrypt_and_verify(cookie).with_indifferent_access end |
参考:https://stackoverflow.com/questions/41474176/how-to-decrypt-a-rails-5-session-cookie-manually