views:

63

answers:

4

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?

+3  A: 

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.

Jaime Bellmyer
I suppose the user_id is not in cookie. Is in session store in cookie. So it's encrypted. An hacker can not really found the user_id easily.
shingara
This case can arrived too.
shingara
I'm a bit confused - did I (or someone) imply that the cookie length was part of the security hole? As for the fix, yeah, I can get the same from using `ActiveRecordStore` for my sessions.
Ben
The cookie store isn't encrypted, it's cryptographically signed. It sounds like I'm quibbling over semantics but it's different.
NZKoz
A: 

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.

shingara
why this downvote :'(
shingara
There were never two users in the database with the same ID. The cookie held in one browser referred to an old ID is all.
Ben
there are. The user with id 1 in first database and another user with id 1 after you reset database. The first user with id 1 is authenticated like user with id 1 in new database.
shingara
Well, we may be quibbling over semantics here but ID ''is'' defined as unique within my user table.
Ben
+1  A: 

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.

NZKoz
This seems simplest and I'll use this for any `CookieStore`-based Rails apps I write in the future.
Ben
A: 

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.

Ben