Migrating existing session cookies while upgrading

Prathamesh Sonpatki

Prathamesh Sonpatki

December 23, 2014

Rails 4.1 introduced JSON serialization for cookies. Earlier all the cookies were serialized using Marshal library of Ruby. The marshalling of cookies can be unsafe because of the possibility of remote code execution vulnerability. So the change to :json is welcoming.

The new applications created with Rails 4.1 or 4.2 have :json as the default cookies serializer.

rake rails:update used for upgrading existing Rails apps to new versions rightly changes the serializer to :json.

Rails.application.config.action_dispatch.cookies_serializer = :json

Deserialization error

However that change can introduce an issue in the application.

Consider a scenario where the cookies are being used for session storage. Like many normal Rails apps, the current_user_id is being stored into the session.

session[:user_id] = current_user_id

Before Rails 4.1 the cookie will be handled by Marshal serializer.

cookie = Marshal.dump(current_user_id) # 42 => "\x04\bi/"
Marshal.load(cookie) # "\x04\bi/" => "42"

After the upgrade the application will try to unserialize cookies using JSON which were serialized using Marshal.

JSON.parse cookie # Earlier dumped using Marshal
# JSON::ParserError: 757: unexpected token at i/'

So the deserialization of the existing cookies will fail and users will start getting errors.

Hybrid comes to rescue

To prevent this Rails provides with a hybrid serializer. The hybrid serializer deserializes marshalled cookies and stores them in JSON format for the next use. All the new cookies will be serialized in the JSON format. This gives happy path for migrating existing marshaled cookies to new Rails versions like 4.1 and 4.2.

To use this hybrid serializer, set cookies_serializer config as :hybrid as follows:

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

After this, all the existing marshalled cookies will be migrated to :json format properly and in the future upgrade of Rails, you can safely change the config from :hybrid to :json which is the default and safe value of this config.

Since this blog was published Rails has changed a bit. You might run into a few gotchas. Dylan has written about how to handle those gotchas here.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.