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
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.
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.