ruby-on-railsactiverecord

Why does Rails use the prefix 2:: in the session_id stored in the database?


I am working on a Rails application that uses ActiveRecord::SessionStore for session management. While debugging, I noticed an interesting behavior regarding the session_id. Here's what I found:

  1. The session_id in the user's cookie looks like this:

    a5ef128d435c9c14f86450b0860d424

  2. However, in the database (sessions table), the session_id is stored in a hashed format with a prefix:

    2::3d05cf25eccf392f19e0049fa0f302a7bd4575a3b3daea9a2cde3173f723f7a0

I understand that the part after 2:: is a SHA-256 hash of the cookie value (session_id), but I’m curious about the prefix (2::):

Here’s how I’m trying to retrieve the session in my code:

current_user_id = lambda { |request|
  session_id = request.cookie_jar["_session_id"]
  return unless session_id.present?

  encrypted_session_id = "2::#{Digest::SHA256.hexdigest(session_id)}"
  session = ActiveRecord::SessionStore::Session.find_by(session_id: encrypted_session_id)
  session&.data&.fetch('user_id', nil)
}

This works as expected, but I have a concern: if the prefix 2:: changes, my code will break.

Any insights or pointers to documentation would be greatly appreciated!


Solution

  • The prefix in front of the session_id comes exactly from Rack::Session (cf. https://github.com/rack/rack-session/blob/498bfdf0757e288aa2cf949044892882628c0a67/lib/rack/session/abstract/id.rb#L31) They add a version ID in front of it probably to manage backwards compatibility with the hashing mechanism as you may have guessed.

    So the prefix may change and it is defined with Rack::Session::SessionId::ID_VERSION so you can replace the code with:

    encrypted_session_id = ‘#{Rack::Session::SessionId::ID_VERSION}::#{Digest::SHA256.hexdigest(session_id)}’
    

    But if the version of the id changes, the old sessions cannot be recovered, which is not viable.

    I think it's better to use the ‘session’ method in the context of a controller and otherwise to use a database retrieval that ignores this identifier but with possible issue.