Rails 4 not encrypting cookie contents - ruby-on-rails

Hello I'm trying to encrypt and secure the data contained in my cookies but It seems like the data only gets encoded (base64)
This is an example:
cookies.signed[:example] = { :value => 'can you see this?', :httponly => true, :expire_after => 30.minutes, :secure => true }
And this is the content of the cookie:
BAhJIhZjYW4geW91IHNlZSB0aGlzPwY6BkVG--b4a8bbd7cd35e392ccd788df0008fd10b48442b2
And if I decode the string (base64) I get:
I"can you see this?:EFom{q{vq{_M<}to8f
I would like to know what I'm missing, currently this is what I have in
session_store.rb:
Service::Application.config.session_store :cookie_store, key: '_service_session'
And in my secret_token.rb I have set something like this:
Service::Application.config.secret_key_base = 'e892d55cbc205bb6..'

Your cookis is not encrypted, because you used the signed method on the cookie jar, which, well, just signes the cookie content.
To encrypt the cookie, use the encrypted method:
cookies.encrypted[:discount] = 45
# => Set-Cookie: discount=ZS9ZZ1R4cG1pcUJ1bm80anhQang3dz09LS1mbDZDSU5scGdOT3ltQ2dTdlhSdWpRPT0%3D--ab54663c9f4e3bc340c790d6d2b71e92f5b60315; path=/
cookies.encrypted[:discount] # => 45

To piggy-back off of the accepted answer:
Depending on your situation: you might want to consider using a session cookie if you desire encryption. (As the accepted answer suggests: you can encrypt cookies, but perhaps a session cookie is more appropriate).
In rails 4 by default: the session cookie is by default encrypted and signed.
Relevant Rails Documentation.
Specific section:
If you only have secret_token set, your cookies will be signed, but not encrypted. This means a user cannot alter their user_id without knowing your app's secret key, but can easily read their user_id. This was the default for Rails 3 apps.
If you have secret_key_base set, your cookies will be encrypted. This goes a step further than signed cookies in that encrypted cookies cannot be altered or read by users. This is the default starting in Rails 4.
secret_key_base is located in rails 4 by default in: config/secrets.yml.
usage in rails 4:
# In rails 4 by default, this will be encrypted and signed
session[user_id] = 1

Related

Resetting unverified session

There are two servers, production.myapp.com and staging.myapp.com that use cookie session store and that cookie is set for myapp.com domain. Is there a way to handle a session cookie that can't be decrypted/verified? Rails version is 5.1.
Take a look at the Documentaion for Cookies. You can use an encrypted cookie and set the domain on the cookie to be myapp.com, i.e.
cookies.encrypted[:my-key] = {
domain: ".myapp.com",
secure: !Rails.env.development?,
value: "put-your-value-here",
}
Note however, that both apps will need to share the secret_key_base since that is what is used to encrypt / read the cookie value.
If you want to delete it be sure to pass the domain as argument.
cookies.delete(:my-key, domain: ".my-app.com")

how to get the persistent cookie value and session cookie value in rails application

Im developing ruby on rails application. I want to get the persistent cookie value and session cookie value in the application. Can any please guide me on this
I have read that request.session_options[:id] will fetch the session_id, is that the one that is usually stored in session cookie? Please guide me if my way of understanding is wrong.Thanks in advance
In Rails, it is simple as calling the session or cookies hash.
# Set a simple session cookie
cookies[:user_name] = "david"
# Read a cookie
cookies[:user_name] # => "david"
# Delete a key
cookies.delete :user_name
The same goes for session.
So, the information that you are looking for is probably inside one of these two.
Take a look at the examples at http://www.tutorialspoint.com/ruby-on-rails/rails-session-cookies.htm

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

Storing an encrypted cookie with Rails

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.
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!
I'm re-posting JacobM's answer, that he deleted, because it was the correct answer and pointed me in the right direction. If he undeletes it, I'll delete this one and pick his as the best answer.
First of all, if you use encrypt_and_verify instead of encrypt it will
sign the cookie for you.
However, when it comes to security, I always prefer to rely on
solutions that have been vetted in public, rather than rolling my own.
An example would be the encrypted-cookies gem.

Accessing the "session key" cookie name from anywhere in Rails

We are building a plugin for Rails to be used within iframe Facebook applications, and at one point we need to check if Rail's session id cookie as been set or not.
By default, this cookie is named _myprojectname_session, what we need to find out is the actual name of the cookie itself. So if it's not set, we can do some redirects to make sure the cookies are set.
How do we access the damn name of the cookie from anywhere? Or at least from within a controller?
Rails.application.config.session_options[:key]
I found the solution. In Rails 2.3.2 at least the session key in set in config/initializers/session_store.rb like this:
ActionController::Base.session = {
:key => '_myapp_session',
:secret => '[...]'
}
And you can read the value like this:
ActionController::Base.session_options[:key]
From Base.session to Base.session_options automagically, doesn't make much sense, and it caused me a big headache... lol
To access the name of the session cookie from within the view or the controller, you can say:
request.session_options[:session_key]
and then to access the raw value of that cookie, being an empty array if it's not set, you use:
request.cookies[ request.session_options[:session_key] ]
The cookie name ( aka session_key ) is set in your config/environment.rb file.
config.action_controller.session = {
:session_key => '_project_session',
:secret => 'long-secret-key'
}
In my experience, if there is an underscore in the key, IE SOMETIMES does not set the cookies. In other words, use 'projectsession' instead of '_project_session'.
I think that the session key is stored in a variable called ENV_SESSION_KEY
Note also this bug which affects tests around session_options in some versions of Rails 2.x: https://rails.lighthouseapp.com/projects/8994/tickets/2303-testrequest-doesnt-initialize-session_options
In Rails 3/4 I'm using this:
request.env["rack.request.cookie_hash"]
This is a hash that contains all the cookies for current user including the one for session.
The hash has as a key the name of the cookie, and as a value the value of the cookie
I couldn't work out how to do this in rails 3 :-(
Eventually I ended up putting this in config/initializers/session_store.rb
SESSION_KEY = '_myapp_session'
MyApp::Application.config.session_store :cookie_store, :key => SESSION_KEY
and then accessing this where needed, eg in a view...
<%= ::ENV_SESSION_KEY %>

Resources