Rails secret token - ruby-on-rails

I'm quite confused what is secret_token used for in Rails. Can anyone explain what it is used for? Is it OK to put this token in a public source repository and use it in production, or I should change it before deploying my app to prevent some kinds of attacks?

Answering my own question - secret_token is used to prevent cookie tampering in Rails. Every cookie has a checksum saved with it, so users won't modify cookie contents (and change saved user id to steal someone's account, for example). The checksum is based on cookie contents and secret_token, so if you are using cookie based sessions you should always make sure your secret_token is really secret, otherwise you can't trust that anything you put into session came back unchanged.

Related

rails: What are the consequences of a leaked secret_key_base

In rails we have something called secret_key_base in config/secrets.yml
What if this production secret is accidentally shared via GitHub (public repo)
What's the worst thing a hacker can do?
Can salted passwords in the users table leak as a result...
Rails by default uses browser cookies as its session store. This means that as opposed to the traditional way of storing session data on the server and only a session id in the cookie, Rails stores the whole session data in the cookie.
This of course would not be very secure in many cases, any user could just see and modify his session contents. So the cookie in Rails is encrypted and signed. The key used for this (encryption and integrity verification) is in secret_key_base.
What this practically means is if this secret_key_base is compromised, any user can decrypt, modify and reencrypt his session cookie (all the data in the session). In some applications this causes no problem as there is nothing interesting stored in the session anyway. But in most cases, it leads to all kinds of problems depending on the actual business logic. For example if privileges were stored in the session, a user could change his privileges in the application, probably an unintended result.
Note that if you use a different session store (like for example Redis), you don't need this secret. Afaik it's only used to encrypt cookies if the cookie store is used for sessions. Using a server-side session store is a good idea and the best practice anyway as it is more secure.

How does session and cookie work in Rails 4?

As I understand one of the strategies to store sessions is store it in the cookie. There is one thing I don't understand from the docs:
To prevent session hash tampering, a digest is calculated from the
session with a server-side secret and inserted into the end of the
cookie.
What does this mean? How do they prevent that, if I get a cookie from another user, and I use it in my browser, I can't pretend I am the other user? I guess I don't understand what session hash tampering means.
How do they prevent that, if I get a cookie from another user, and I
use it in my browser, I can't pretend I am the other user?
This is called session hijacking, and is covered in http://guides.rubyonrails.org/security.html#session-hijacking. The recommended way to to mitigate this is by "always forcing SSL connection in your application config file", like so:
config.force_ssl = true
The whole http://guides.rubyonrails.org/security.html is definitely worth a read, for more goodness like this.

How does rails/devise handle cookie sessions?

I'd like to understand what's really going on when signing in a user with rails/devise.
I've created a minimal rails app, installed devise and created a User devise model.
Everything works fine, and when I log in (using remember me) I get a session cookie just as expected.
Now what's bugging me is : How does rails handle the session informations that the browser is passing through the cookie ?
I'd naively expect some information to be stored in the database, but I don't see where. There's no such thing as session table, no session column in Users, and I couldn't find anything of interest in the tmp dir.
Note that restarting the server wouldn't kill my session. It is of course expected, but now I'm really wondering what kind of magic is happening here ?
in other words : how does the server check the validity of a cookie to authenticate a user ?
Thanks !
The default rails session storage is CookieStore. This means that all the session data is stored in a cookie rather than in the database anywhere. In Rails 3.2 the cookie is signed to prevent tampering, but not encrypted. In Rails 4 it's generally encrypted by default. The fact that it's in a cookie is how it persists across restarts of your server. It also means you can only store 4k of data and you wouldn't want to store anything sensitive in there in Rails < 4. It's best to keep a minimum of data in the session anyway.
You can also opt for storing the session data in the database and only having a session id in a cookie.
This answer I gave the other week has some extra info that might be useful:
Sessions made sense to me before I started reading about them online
Also, the rails api doc for CookieStore gives a nice summary:
http://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html

How do I prevent Rails users from accidentally authenticating as the wrong user?

Specifically, I have written a Rails app in which I'm using the default (in Rails 2.3.5) CookieStore session store and I've spotted an odd problem in development.
Myself and a few others had been using the site for a few weeks and we each had a login based on a username and password (each user registered themselves and I stored the (salted and hashed) data in the database). I was storing the user ID in the Rails session object (and, therefore, in the cookie that is passed back and forth between browser and server).
One important point here: since this is an intranet site, I set the cookies to stay alive for up to 2 weeks to avoid users having to log in all the time.
Today I reset the database, wiping all user records (and all other data, intentionally). A few users started registering themselves again and then one user found that the first time they went to the site since the wipe they were automatically logged-in as a different user!
I think I can see why this happened: the user ID passed from that user's browser to the server now matched a different user-record in my database. My initial thought was "oh dear, I wasn't expecting that!" but the more I thought about it the more I realised this was probably expected behaviour.
I realise I can change my Rails app to user ActiveRecordStore but before I did that I wanted to make sure I understand what's going on here. Specifically, does the combination of using CookieStore sessions and having the sessions stay alive for some time really create such a gaping security hole? Or am I missing something? Should the session_id be providing a little more security here?
The big security hole in this setup isn't the cookie length, it's setting the user_id in a cookie. This means that anyone who logs into your site can log in as anyone else just by changing that cookie! A hacker would just sequentially walk through user_id's, logging in and seeing if there's anything they want to steal or abuse.
If you want to roll your own authentication, try this instead: add a "token" string field to your user table. When somebody logs in, set this token to a random set of numbers and letters, and pass that as the cookie back to the user. The token should be at least 32 characaters, alphanumeric, upper and lower case.
Now when a user goes to a page, their account is looked up by that hash instead of their user_id. The value is that the hash is much harder to guess, and will never be repeated. Your user_id's were actually repeated when you reset the database, causing people to be logged in as each other.
UPDATE
#shingara is right that the cookie store does handle the security part already, my mistake. The user_id mixup is therefore a one-time occurrence because you reset the database. This is not a problem you'll face in a production environment, unless you reset the database again. If resetting is ever a possibility, then still do the token creation as I recommended. Otherwise, you're fine.
The simplest solution to the problem you had here would be to have changed the cookie name when you reset the database. The cookie name should be in config/initializers/session_store.rb
ActionController::Base.session = {
:key => '_your_app_session_v2',
You could also change the secret, but that may generate errors for your users if they request the site with an old cookie.
You case arrived only if you have 2 differents user with the same user_id. So it's not possible if you define the user_id like unique.
Another case, you can add in session, an hash with an unique key by user. when you check the session you get the user_id and check if the user_token is same . If not, the user is not authorized.
Thankyou for all the responses. They all answered my question in a way: yes, my setup (and my not setting a new session key after wiping the users) creates a security hole.
Lots of Rails tutorials advocate this setup without mentioning the fact that all you need is to monkey with your cookie to be fully authenticated as another user.
So, to summarise, I asked the question because I couldn't find anything discussing the danger of CookieStore session + long cookie lifetimes, and I found that surprising so thought I might be missing something obvious.
I had a similar issue and resolved it using a code snippet similar to
this comment by mdesantis on managing Rails secret token

Implementing sessions in rails

I'm doing a first pass at rolling my own authentication and sessions in rails and am not sure that I understand the session support that is present. (By first pass, I mean I'm initially authenticating via http, not https. Production code will use https.)
My understanding of secure sessions is that you pass a token to the browser via a cookie over SSL, and then compare that token with the token stored on the server to see if it's really the user you think it is. I was hoping you guys could check my understanding of secure sessions, which is as follows:
User gets login page and submits login name and password (POST via SSL).
Server checks protocol and then checks sha1 of password (+ salt, usually) against existing hash in db. If they match, generate a session id, put it both in a(n SSL) cookie with the user id and in a server-side session store. Redirect user to the secured area of the site.
That session id remains the same throughout the user's logged in session --or-- the server issues a new session id after each secure operation, sending it via an SSL cookie and storing the new value in the db.
Any actions that involve private or secure data checks the session store for the existence of a session id for this user and, if present, compares the cookie's session_id against the session store before performing the action. If we're rotating session ids, issue a new session id (SSL cookie and server-side store) after the action.
User logs out, which tells the server to remove the session id from the session store and clear the cookie. Or the cookie expires on the browser and/or on the server and re-authentication is required.
Are there any glaring errors in the above? Also, it seems like Rails' session[] support wouldn't prevent MITM attacks if the token in the cookie was merely a session id. Is that correct?
I would suggest having a look at restful_authentication. This is the defacto standard auth library for Rails.
You don't actually need to generate the session_id yourself ... Rails handles all of this for you - checking the session id against the value provided by the browser. You can actually just store the user id in Rails session collection and then check that this exists.
You would technically be vulnerable to MITM attack if you do not use an SSL connection.
You seem to be confusing 'the session' and 'being logged in'. The session object in Rails is just a hash, stored in a cookie, and it is always present—regardless of whether or not the user has logged in.
As you outline, the most common procedure is to store the user's ID in the session.
The restful_authentication plugin does a lot of things. Perhaps you find my Blank Rails App more helpful, as it does something similar with a lot less code. Take a look at the sessions controller and lib/authentication, where the authentication related controller code is defined.
Try this web site, http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails. It appears to have a pretty comprehensive coverage of the subject.
One suggestion that I would have would be to not only use SSL but also encrypt and encode (Base 64) the session and other cookies that you send. Include a nonce (random value) with the session id so that the encrypted/encoded version changes every time you send it. If you are genuinely concerned about the session being hijacked you could also regenerate the session id periodically to limit the exposure of a hijacked cookie, although encrypting it should protected you if the cookies aren't persistent.
You should be able to use the encryption/encoding idea even if you use query parameters for the session id instead of cookies.

Resources