Inadvertent Session Hijacking Issue With Restful Authentication - ruby-on-rails

I'm using the current version of restful_authentication that is found on github and I'm having a bunch of strange session issues. The server seems to be somehow assigning sessions to users it shouldn't be. This only happens when crossing the logged out/logged in barrier.
Here's an example. With no sessions active on the server, I log in to an account with user A. On another machine, I log in with user B. Then when logging out of user B, sometime after the logout redirect happens, I will be logged in as user A. From this point, I can continue to navigate the site as if I had logged in as that user! Something I've observed via the logs is that when this hijack happens, the session IDs are not the same. User A is logged in in both sessions, but the session ID's are completely different. This is just one example of what might happen. I can't reproduce the issue reliably as it is seemingly random.
It doesn't seem to be a symptom of the environment or the server it's running on. I can reproduce the problem using both mongrel and passenger. I've also seen it in development and production. I am using db-based sessions in this application and it is running on Rails 2.1.1. I applied the stateful option when calling the generator. Otherwise no other modifications have been made to how sessions are handled.
Update
Here is the offending method which came directly from restful_authentication.
# Accesses the current user from the session.
# Future calls avoid the database because nil is not equal to false.
def current_user
#current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless #current_user == false
end

This can happen if you (or those who wrote restful_authentication) are caching the current user in a class variable. I've seen a bunch of articles advocating the use of "User.current_user", but since classes are cached across requests, this can cause session tainting.

I don't know if this is so much of an answer as it is a work around. All I did was switch over to cookie based sessions and everything is working smoothly.

Is this site remote? Are you logging into it onto two separate computers on the same network?

Related

User.IsInRole fails for one action but not for another

I've put a custom authorize attribute into my MVC application, which does
if (!this.Roles.Split(',').Any(filterContext.HttpContext.User.IsInRole))
and if true it will redirect you to unauthorised.
I put this attribute on my controller at controller level.
One action works fine, and in one action I get unauthorised.
Is there some bug or problem in the role system? I've read that logging out and in can force some cache to refresh or something, however the system I am using authenticates with your domain credentials so there is no way to log out.
I've tried restarting the app pool and deleting my session cookie but nothing has worked.
Has anyone experienced this specific issue before or has some guidance on perhaps flushing any caching related to it (assuming it's a caching issue)?
ETA: Another user on the system gave himself the role required for the controller and both actions work fine for him. So perhaps my user is somehow bugged. This is on UAT so slightly more difficult to debug than running on my local machine (which works fine).
ETA2: I'm pretty sure this is a caching issue, as going to the URL with ?1=1 in the query string, it works. I'm unable to invalidate the cache though. This may be a problem in the future when assigning roles to people.
First, we need more code before we could possibly give you any definitive answers. However:
Caching could be a problem. If you're using anything like OutputCache, you should ensure that you're using VaryByCustom and somehow including the user's id or other identifying token in the custom string returned.
If you're adding roles to users, you must either log the user out and sign them back in, or otherwise invalidate their authorization. In Identity, for example, you can simply invalidate the security stamp, which will cause the user to be reauthorized, updating things like claims or roles that have changed since they signed in.

How to check if a user just started a new session?

I want to determine if a user just started a new session in my Rails app. I am currently using HTTP referer to define what a new session is. But I am not sure if this is the correct way. The following code is written in Ruby.
if !request.referrer || !request.referrer.start_with?(request.protocol + request.host_with_port)
# If the user came from another site or came here directly, then we regard it as a new session
else
# Not a new session
end
You can store an attribute in the session the first time the user visits. If the attribute is set then you can safely conclude they've visited your website before.
If, however, the attribute is not set then it could mean many things:
the user is visiting your site for the first time
the user may have deleted their cookies, and you can't tell that they're returning
the user may visiting from different browser or on a different device too
This is how you would code it up
if session.has_key?(:visited_before)
# user has visited before
else
# new user
session[:visited_before] = true
end
You should be wary of
where the sessions are being stored and memory limitations, but I wouldn't let this stop you from getting started unless it's a high traffic website.
googlebot and other search engine crawlers, you can detect those in the user agent headers and avoid setting the session.

Rails 3 application creates sessions only for certain users in my db

This is an extremely weird situation. I have a Rails 3 app that authenticates users using OmniAuth. The problem I recently encountered is that after correctly validating a user using the aforementioned gem, at some part of the code I set some session variables, specifically:
session[:user_id] = user.id
The problem is, that this line only works for some users (it does not depend on the browser, the cookies, nothing, only for certain users. The user variable is valid and has an id attribute, but this session variable does not persist on the next request, sending this user back to the login page. Again, this only happens to some users, which makes the problem a whole lot more difficult to debug.
Any ideas? Thanks in advance!
PS: I've tried using the cookie session store and the database session store, both with the same results.
EDIT: The problem ended up being something completely not related to sessions.

Rails user switches session

I've got a Rails application running and it seems that every once in a while a user gets the cookie session_id value from a different user.
I use active_record_store to keep track of the session in Rails.
The current_user method:
def current_user
#current_user ||= session[:user_id] ? User.find_by_id(session[:user_id]) : nil
return #current_user
end
I run 8 ruby processes on a Windows machine using Apache 2.2.15. Sometimes it serves the incorrect session_id to the user. My rails version is 2.1.2
In the log file I can see the user changes session_id of a different user.
For instance:
Processing Manage::TruckController#show (for 179.34.103.8 at 2011-05-12 07:35:24) [POST]
Session ID: 1fbc801bbade1007291901ca810bfeda1eab76
....
Completed
And 5 minutes later is would get a different session id, however belonging to a valid user.
Processing Manage::TruckController#edit (for 179.34.103.8 at 2011-05-12 07:40:01) [POST]
Session ID: 2f8e84c40c490c509feabbce9701aa9101ba0f
....
Completed
To me this seems that Rails is handing out incorrect session_id data to the cookie that is stored on the web browser of the user.
Any suggestions on this?
From looking at the code and
the security guide, it seems like there is a slight possibility of MD5 collision. It's very unlikely that this would happen or be reproducible though, so I'm more inclined to say it has something to do with the browser testing.
I'd first make sure that your browser isn't serving up these bad session IDs by using a tool like Charles.
I also recommend using the cookie session whenever possible which would avoid this sort of problem.
Finally, since you're running a fairly old version of Rails it might be worth trying an upgrade. It's possible you're hitting an old bug.
I found this extremely useful.
how-do-i-prevent-rails-users-from-accidentally-authenticating-as-the-wrong-user
If you are:
destroying your database in development
AND
using the out-of-the-box Rails secret_token.rb
The client browser will have preserved a valid session containing a user_id that may or may not belong to that user.
I had a similar issue and resolved it using a code snippet similar to
this comment by mdesantis on managing Rails secret token

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

Resources