17

I have an app that is using devise for authentication. Rails 3 on ruby 1.9.2, with passenger on top of nginx.

Here is my problem: I have noticed that occaisionally my sessions are getting crossed. While being logged in as one user, I sometimes become another user. This is really a horrible problem. I have managed to get it to stop by using active_record sessions storage. But I am stumped as to where it could be happening. It happens both when using cookie storage, and memcached storage. I am not sure where to start debugging. I have gone through all of my code, and I am only reading from 'current_user' not writing. I don't have any code storing items in session.

Can anyone give me suggestions as to where, or how this could be happening?

Update:

I setup a div at the top of the page to dump the session contents on each request. It is not just the user switching, it is the whole session. There are some dummy variables that I set in the session just to see what would happen. When the sessions get crossed, (User A becomes User B) User A now sees the dummy variables that User B had. And User B is logged out.

UPDATE 2

I found another question here on stack overflow that describes the same exact problem: In Rails, what could cause a user to have another user's session?

It looks like it could be a passenger issue? But more important, how come it is even happening? This is a REAL big problem. How do I put a stop to this?

UPDATE 3

I am now using Unicorn to serve my app. I set config.threadsafe! and started using active-record sessions exclusively. No more memcached sessions. The problem is gone. At least I can stop pulling my hair out because the security hole is plugged.

I would still like to know what exactly was causing it. Most of the tutorials out there show how to setup passenger, with the default spawning method. Naturally, I would think memcached would perform best for session management over the other methods. Especially in a multiple application server environment.

Update 4

Okay, last and final update. This was an issue with forked processes using the same memcached connection. I fixed it by using dalli memcached client, and reseting the connection in the after_fork callback of either unicorn or passenger.

Community
  • 1
  • 1
demersus
  • 1,185
  • 2
  • 10
  • 24
  • Are you using the different users in the same browser? Or is it just a completely random other user that you've not used recently? – Chris Kimpton Jan 21 '11 at 13:30
  • Not logged in with separate users in same browser. This happens even on separate networks. User A might become User B. Even though they are at separate locations. It happens randomly and the only thing that I have found is that they both have to be logged in for it to happen. – demersus Jan 21 '11 at 15:35
  • Is it possible that it could be a passenger issue? Does devise/warden cache the current_user variable? – demersus Jan 21 '11 at 15:37
  • I'd add debugging everywhere...maybe some piece of code isn't thread safe? – rogerdpack Jan 21 '11 at 19:01

2 Answers2

5

I'd be willing to bet you're using Passenger's (default) smart spawning, and falling victim to the Spawning Gotcha.

Set your PassengerSpawnMethod to 'conservative' and see if this goes away. This easily accounts for the memcache case, unless you are protecting against it. Presumably a similar problem in devise (or your code).

Do you see sessions cross across physical servers, or only on one server?

girasquid
  • 15,121
  • 2
  • 48
  • 58
user510365
  • 196
  • 3
  • Currently I am running passenger with the default spawning method on one machine. The current session variable must not be getting cleared correctly between requests. I can't imagine, with the default settings, this has not been noticed as a problem by other people. I will try the conservative spawn method, but this kind of defeats some of the benefits of using passenger. – demersus Jan 24 '11 at 16:19
  • If it was really the session variable, it would also affect activerecord sessions, right? So i don't think thats it. Memcache problems like this are EXPLICITLY called out in the passenger documentation (in that gotcha), so you should make sure you have that covered, and if not, fix and go back to memcache sessions. Can you reproduce in a dev environment? – user510365 Jan 27 '11 at 22:34
  • This issue was put to rest temporarily by using the activerecord sessions. Recently I tried using Unicorn to serve the app, and it seems to be happening with Unicorn as well. – demersus May 18 '11 at 16:44
1

It is very likely that this bug can be fixed by upgrading to rack-cache 1.2 or higher. This is what might be happening:

  1. User A requests a page. A session is created and a Set-Cookie header is returned in the response.
  2. Rack-cache incorrectly caches the Set-Cookie header with the session ID of User A.
  3. User B requests the same page and rack-cache serves the cached response, including the Set-Cookie header with the session ID of User A.

These two tickets discuss this problem: https://github.com/rails/rails/issues/476 and https://github.com/rtomayko/rack-cache/pull/52

Finally, this issue is mentioned in the release notes for rack-cache 1.2: https://github.com/rtomayko/rack-cache/blob/master/CHANGES

Also notice, that even when you are NOT using the cookie session store, the session ID is still stored in a cookie, so this bug might still bite you even when you're not using the cookie store.

Hope this helps.

Johannes

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165