Changes
-This method helps you to **manually** decrypt the session cookie in Rails 5.2. Chrome can retrieve the session cookie string from `Dev Tools > Application > Cookies > _application_name_session`.- +Normally, Rails handles encryption and signing of cookies, and you don't have to deal with the matter. Should you need to decrypt a session cookie manually: here is how.
-By default Rails >= 5.2 app uses JSON as cookie serializer. Before Marshal was used to serialize cookies. You can find out your application's cookies serializer with `Rails.application.config.action_dispatch.cookies_serializer`.- +Obviously, you can only decrypt a session cookie from within the corresponding Rails application. Only the Rails application that encrypted a cookie has the secrets to decrypt it.
- +
- +## Rails 7
- +- With [authenticated encryption](https://guides.rubyonrails.org/v7.0/configuring.html#config-action-dispatch-use-authenticated-cookie-encryption) enabled (default since Rails 5)
- +- With [embedded cookie metadata](https://guides.rubyonrails.org/v7.0/configuring.html#config-action-dispatch-use-cookies-with-metadata) enabled (default since Rails 6). On mismatching `purpose`, `#decrypt_and_verify` will simply return `nil`.
- +
- +```ruby
- +def decrypt_session_cookie(cookie_string)
- + return if cookie.blank?
- +
- + cipher = ActiveSupport::MessageEncryptor.default_cipher
- + key_length = ActiveSupport::MessageEncryptor.key_len(cipher)
- + key_generator = Rails.application.key_generator
- + salt = Rails.configuration.action_dispatch.authenticated_encrypted_cookie_salt
- + secret = key_generator.generate_key(salt, key_length)
- + encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
- +
- + cookie = CGI::unescape(cookie_string.strip)
- + session_name = Rails.application.config.session_options[:key]
- +
- + encryptor.decrypt_and_verify(cookie, purpose: "cookie.#{session_name}")
- +rescue ActiveSupport::MessageEncryptor::InvalidMessage
- + nil
- +end
- +```
- +#### References
- +- [ActionDispatch::Cookies::EncryptedKeyRotatingCookieJar](https://github.com/rails/rails/blob/v7.0.8.6/actionpack/lib/action_dispatch/middleware/cookies.rb#L645)
- +- [ActiveSupport::MessageEncryptor#_decrypt](https://github.com/rails/rails/blob/v7.0.8.6/activesupport/lib/active_support/message_encryptor.rb#L186)
- +
- +## Rails 5
- +By default Rails >= 5.2 app uses JSON as cookie serializer. Before, Marshal was used to serialize cookies. You can find out your application's cookies serializer with `Rails.application.config.action_dispatch.cookies_serializer`.
- ```rb
- # Available modes: json, marshal
- def decrypt_session(cookie_string, mode = 'json')
- serializer = case mode
- when 'json' then JSON
- when 'marshal' then ActiveSupport::MessageEncryptor::NullSerializer
- end
- cookie = CGI::unescape(cookie_string.strip)
- salt = Rails.configuration.action_dispatch.encrypted_cookie_salt
- signed_salt = Rails.configuration.action_dispatch.encrypted_signed_cookie_salt
- key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secret_key_base, iterations: 1000)
- secret = key_generator.generate_key(salt)[0, 32]
- sign_secret = key_generator.generate_key(signed_salt)
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: serializer)
- result = encryptor.decrypt_and_verify(cookie)
- (mode == 'marshal') ? Marshal.load(result) : result
- end
- ```
- Example session cookie:
- ```rb
- decrypt_session 'K2lUcDA1MjQ4b05RRU9zU2tNM05ldmIvdGpKVzNDdmRNNVkvbHFVSkNwT1lGODhkN3NZZHRYaDBwQXowR2lheUoxemt1Wm82Z0psYlFNVFM2dmxQaVNvRlhRZGNQQzNXUkswNnNTdVRPR1o5UURrY29CUjJvbEtXb2dwS2dTazZneG5XbjBzMVZISEVyc3ZkQzIxRW9FU3JERHZMWFg3Uk50Z2o0cVZ1eUF2VVR2RjdFbDUvaXlqUEorMEd6NGM0WjBhaTZOQ0NPaGE1NkZCTmVjMzdHajZueU56TVpQZk53bVJKZ21KWW9SdXFuc09WZVlMNS93aERSRlhLTWpEN3Y2M2xtSTlrUjNoS0lNQVMxNUhLNkpDekhhcUViZklLa0pSV3A2NzBtZmc9LS0yS1RmVTJyanl5dHpWQklkSlFQbVJRPT0%3D--50da898541a727755da8cffffbcfbb2c5dd3310b'
- => {
- "session_id"=>"8ef662867ab2457717ba74c143c08733",
- "timestamp"=>1572261371, "warden.user.user.key"=>[[3],- "$2a$13$FlVrgrbRbFRaFun/4dhaK."],- + "timestamp"=>1572261371,
- + "warden.user.user.key"=>[[3], "$2a$13$FlVrgrbRbFRaFun/4dhaK."],
- "_csrf_token"=>"e03pX09Pqfj3syQp0w9AAJ3fEh7I9Sm8VhndHfqQxgw="
- }
- ```
- This method is based on [Decrypt a Rails 5 session cookie](https://gist.github.com/erose/36a514bc5ac9c5f18552369265b4d449) and extended with the cookies serializer section. You will get an exception like `ActiveSupport::MessageEncryptor::InvalidMessage` when you use the wrong cookies serializer.
Posted by Dominik Schöler to makandra dev (2024-11-22 13:39)