pseudopeach
pseudopeach

Reputation: 1475

encrypting session information in rails

By default, rails uses cookie storage for session information. The tutorial I followed said that it was the best way and super fast, and that it all gets encrypted. But when I base64 decode the cookie content, I can see my session info there. It's mixed into a lot of garbled characters, but it's there.

What am I missing here?

Doesn't rails use that secret token thing to encrypt the info in the cookie? How can I make it do so?

Upvotes: 1

Views: 1188

Answers (1)

Chris Heald
Chris Heald

Reputation: 62668

Rails uses a secret token to sign the session. The raw data is still there, but changing it will cause it to not match the signature any more, and Rails will reject it. The cookie string looks like session_data--signature, the session data is a base64-encoded marshalled object, and the signature is HMAC(session string, secret token).

The general assumption of the session data is that it is not secret (since it generally should contain only a few things, like a CSRF token and a user ID), but it should not be changeable by a user. The cookie signing accomplishes this.

If you need to actually encrypt the data so that users could never see it, you could do so using something like OpenSSL symmetric encryption, or you could switch to a non-cookie data store.

This is a variant on my own app's cookie store; I haven't tested it, but in theory this should generate actually-encrypted cookies for you. Note that this will be appreciably slower than the default cookie store, and depending on its runtime, could potentially be a DOS vector. Additionally, encrypted data will be lengthier than unencrypted data, and session cookies have a 4kb limit, so if you're storing a lot of data in your session, this might cause you to blow past that limit.

# Define our message encryptor
module ActiveSupport
  class EncryptedMessageVerifier < MessageVerifier
    def verify(message)
      Marshal.load cryptor.decrypt_and_verify(message)
    end

    def generate(value)
      cryptor.encrypt_and_sign Marshal.dump(value)
    end

    def cryptor
      ActiveSupport::MessageEncryptor.new(@secret)
    end
  end
end

# And then patch it into SignedCookieJar
class ActionDispatch::Cookies::SignedCookieJar
  def initialize(parent_jar, secret)
    ensure_secret_secure(secret)
    @parent_jar = parent_jar
    @verifier   = ActiveSupport::EncryptedMessageVerifier.new(secret)
  end
end

Upvotes: 3

Related Questions