Sessions are getting crossed. Ruby on Rails
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 开发者_JAVA百科either unicorn or passenger.
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?
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:
- User A requests a page. A session is created and a Set-Cookie header is returned in the response.
- Rack-cache incorrectly caches the Set-Cookie header with the session ID of User A.
- 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
精彩评论