I need to store a small piece of data (less than 10 characters) in a cookie in Rails and I need it to be secure. I don't want anybody being able to read that piece of data or injecting their own piece of data (as that would open up the app to many kinds of attacks). I think encrypting the contents of the cookie is the way to go (should I also sign it?). What is the best way to do it?
Right now I'm doing this, which looks secure, but many things looked secure to people that knew much more than I about security and then it was discovered it wasn't really secure.
I'm saving the secret in this way:
encryptor = ActiveSupport::MessageEncryptor.new(Example::Application.config.secret_token)
cookies[:secret] = {
:value => encryptor.encrypt(secret),
:domain => "example.com",
:secure => !(Rails.env.test? || Rails.env.development?)
}
and then I'm reading it like this:
encryptor = ActiveSupport::MessageEncryptor.new(Example::Application.config.secret_token)
secret = encryptor.decrypt(cookies[:secret])
Is that secure? Any better ways of doing it?
Update: I know about Rails' session and how it is secure, both by signing the cookie and by optionally storing the contents of the session server side and I do use the session for what it is for. But my question here is about storing a cookie, a piece of information I do not want in the session but I still need it to be secure.
Rails provides a special kind of cookie called a session cookie which, as the name suggests has an expiry of Session. This is an encrypted cookie and stores the user's data in a Hash . It's a great place to store things like authentication tokens and redirect locations. Rails stores Flash data in the session cookie.
Decrypt the cookie and check the digest: Decrypt de key of the cookie: do Base64 decoding, then decrypt it using your institution's private RSA key. Decrypt the data using the decrypted AES key. Check the digest using secutix public certificate. The following example in java will show you how to proceed.
Rails Encrypted Credentials Use AES 128-bit Key.
Secure Flag If the browser sends cookies over unencrypted connections, it will be possible for hackers to eavesdrop on your connection and read (or even change) the contents of your cookies. To prevent this, send cookies over encrypted connections only.
Setting a secure cookie
cookies.signed[:secret] = {
:value => "foo bar",
:domain => "example.com",
:secure => !(Rails.env.test? || Rails.env.development?)
}
Accessing the cookie
cookies.signed[:secret] # returns "foo bar"
The cookie is signed using ActionController::Base.cookie_verifier_secret. You can set the cookie_verifier_secret
in the initializer file.
As KandadaBoggu says, it looks like what you want is a session variable, and session variables are by default encrypted and stored in cookies. However, if you have a look at the contents of config/initializers/session_store.rb
you will find something like the following:
# Be sure to restart your server when you modify this file.
MyRailsApp::Application.config.session_store :cookie_store, :key => '_my_rails_app_session'
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
# MyRailsApp::Application.config.session_store :active_record_store
Which suggests to me that you should use the database for sessions instead of the cookie-based default, which shouldn't be used to store highly confidential information. The pre-cooked migration makes everything really easy to set up so there's very little overhead in doing so, and once it's done there's basically zero overhead if you need to add a new piece of secret information at a later date!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With