Action Dispatch
provides cookies.signed
and
cookies.encrypted
,
which can be used to prevent users from tampering with a cookie’s value.
Example:
# Prevents users from tampering with this cookie’s value
cookies.signed[:proxy_id] = current_admin.id
# Resultant client side cookie's content
# MTAx--fd47225e9e6de0710a4f84104d73fec1e4d94c65
# Prevents users from reading and tampering with its value
cookies.encrypted[:current_zip] = current_user.zip
# Resultant client side cookie's content
# aHNzb2dxVkN1bE1MQTd0MnFsSkZ2dz09LS1tM2NHcVZQbjRoT0RVOVdvdE9FdHZnPT0%3D--be007d00dda3678f79fda9d2a7bcfacc6a760919
The problem
Before Rails 6, the methods described above only signed the content of the cookie and not the name.
This created a security vulnerability where signed data could potentially be copied from one cookie to another.
This issue presented a case where it is possible to copy the value of a cookie and use it for another.
After Rails 6
Rails 6 adds purpose
metadata to cookies.
A cookie’s name is used to set this metadata, which is then embedded in the cookie.
This prevents users from using one cookie’s value for another.
Example:
cookies.signed[:proxy_id] = current_admin.id
# Resultant client side cookie's content
# eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik1UQXgiLCJleHAiOm51bGwsInB1ciI6ImNvb2tpZS5wcm94eV9pZCJ9fQ%3D%3D--ac22ece5b73ea1fbd3de8e925be57a173e9f8a2b
In the example above, the data before --
is the Base64
encoded value with purpose
and expiry
metadata embedded.
Cookies previously set without this metadata will continue to be honored.
We can opt out of this feature with the following config:
config.action_dispatch.use_cookies_with_metadata = false
The above config is true
by default.