I have a bug with storing sessions in memcache.
The bug is reproduced, if I log in and try to open around 25 different pages at the same time (different tabs). Sometimes my user gets logged out. The funny thing is that the session is kept, but security context is removed. And even funnier thing is that this security context is restored (probably with other request). And the funniest thing is that if I set default filesystem session storage - everything works as expected.
Sessions are stored on Amazon Elasticache.
If I check my user session on Amazon during those requests - there happens something like this:
Request 1 - My session has sf2_ attributes key and _security_main key
Request 2 - My session has sf2_ attributes key and _security_main key
Request 3 - My session has only sf2_ key
Request 4 - My session has sf2_ attributes key and _security_main key AGAIN
I believe it has something to do with the concurrency.
I've tried lot different things, but I am out of ideas currently. Any tips are much appreciated!
Technical info
Symfony version 2.1.0-DEV
security.yml
Please, let me know if you need more details.
The problem was caused by the different time, configured for php script execution time and memcache session lock. I had 60 seconds for php and 15 seconds for memcache.session_lock
So, what happened under the hood:
Script A starts, locks session, takes up to 60 seconds
Script B starts, waits for session to be unlocked
After 15 seconds of Script A execution, memcache unlocks session.
Script B intrudes in the flow and "corrupts" the session
So I have increased memcache.session_lock time to match php execution time - and the problem had gone.
Symfony 2.1 is End of Maintenance. This means no bug fixes anymore, only security fixes until End of Life in 11/2013.
You should update to Symfony 2.3 LTS, which has a maintenance period of 36 months. Maybe this is already fixed. If not, raise an issue in the project.
Btw. you can try the memcached handler instead of memcache. Mentioned in #8407
Related
We have 2x pfSense FW's in HA, behind that, 2x Zen Load Balancers in Master/Slave Cluster, behind those, 3x Front End web stack servers running NGinx, PHP-FPM, PHP-APC. In that same network segment, there are 2x MySQL DB Servers in Master/Slave replication.
PHP sessions on the front ends should be "cleaned up" after 1440 seconds:
session.gc_maxlifetime = 1440
.
Cookies are expired when the users browser closes:
session.cookie_lifetime = 0
Today, we were alerted by an end user that they logged in (PHP based login form on the website), but were authenticated as a completely different user. This is inconvenient to say the least.
The ZLB's are set to use Hash: Sticky Client. They should stick users to a single Front End (FE) for the duration of their session. The only reason I can think of this happening is that two of the FE's generated the same PHP Session ID, and then somehow the user was unlucky enough to be directed to that other FE by the LB's.
My questions are plentiful, but for now, I only have a few:
Could I perhaps set a different SESSID name per front end server? Would this stop the FE's generating session ID's that were the same? This would at least then result in the user getting logged out rather than logged in again as a different user!
We sync the site data using lsyncd and a whole bunch of inotifywatch processes, but we do not sync the /var/lib/php directories that contain the sessions. I deliberately didn't do this... I'm now thinking perhaps I should be syncing that. lsyncd will be able to duplicate session files across all 3 front ends within about 10seconds of the sessions being modified. Good idea as a temporary fix?
Lastly, I know full well that the client should be using the DB to store sessions. This would completely eradicate it being able to duplicate the session ID's. But right now, they are unwilling to prioritise that in the development time-line.
Ideas very much welcome as I'm struggling to see an easy way out, even as a temporary measure. I cant let another client get logged in as a different user. It's a massive no-no.
Thanks!!
Judging by your question you are somewhat confused by the problem - and its not clear exactly what problem you are trying to fix.
Today, we were alerted by an end user that they logged in (PHP based login form on the website), but were authenticated as a completely different user
There's potentially several things happening here.
Cookies are expired when the users browser closes:
Not so. Depending on how the browser is configured, most will retain session cookies across restarts. Since this is controlled at the client, its not something you can do much about.
PHP sessions on the front ends should be "cleaned up" after 1440 seconds
The magic word here is "after" - garbage collection is triggered on a random basis. Session files can persist for much longer and the default handler will happily retrieve and unserialize session data after the TTL has expired.
Do you control the application code? (if not, your post is off-topic here). If so, then its possible you have session fixation and hijack vulnerabilities in your code (but that's based on the description provided by the user - which is typically imprecise and misleading).
Its also possible that content is being cached somewhere in the stack inappropriately.
You didn't say if the site is running on HTTP, HTTPS or mixed, and if HTTPS is involved, where the SSL is terminated. These are key to understanding where the issue may have arisen.
Your next steps are to ensure that:
you have logout functionality in your code which destroys the session data and changes the session id
that you change the session id on authentication
That your session based scripts are returning appropriate caching information (including a Varies: Cookie header)
It is highly improbable that 2 systems would generate the same session id around the same time.
Really you want to get away from using sticky sessions. It's not hard.
You've got 2 layers at your front end that are adding no functional or performance value, and since you are using sticky sessions, effectively no capacity or resillience value!!! Whoever sold you this is laughing all the way to the bank.
Our user has requested to have long session time out (8 hrs) for our php application .I was just wondering about the disadvantages of doing so in production server. In this case will it increase the resource management on the server and will the user be ever logged out in the event where the user makes a request to the website after every 5 hour?Any suggestion would be appreciated.
Thanks
If there's a longer sessions that would mean more data to be stored on the server at the same time, since sessions do not destroy that fast.
Beyond that, longer sessions would just mean less memory used to create/delete session data.
Let's say there's a site/system with a logged in member area, and users are rarely, but very inconveniently logged out while working with the site/system.
It's doubtfully session expiring, since the user was not idle for very long. And even if they were idle, I added a periodic AJAX request, a so called heartbeat, which updates the sessions' access time, and modified time. I even added a touch($session_file) every time a user clicks something or a heartbeat is called. I tried regenerating session ID as well. Nothing helped.
And unfortunately, so far, I was not able to reproduce the problem locally, because it happens every so often, when there's more requests. Some php.ini parameters:
session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_lifetime = 0
session.gc_probability = 1
session.gc_divisor = 1500
session.gc_maxlifetime = 10800
Since sessions and authentication is already handled via one super controller in your code, it should be easy to at least rule out session destruction.
Typically only the login page creates a session, so at this point you can (and should) add a known value inside, such as the session id.
The other pages (including your heartbeat) resume an existing session, so at this point you look for the above value; if it's missing, you can do a few more checks:
was a session cookie passed? if not, browser / cookie issue.
does the session cookie correspond with session_id()? if not, session file was lost due to garbage collection.
does the known value exist in the session? if not, session was truncated or someone is trying to do session adoption attack.
does the known value correspond to the session cookie? if not, the session was established via different means than cookie; you could check session.use_only_cookies setting.
The above set of checks should point you in the right direction.
I presume you are using built in PHP file session storage? There are known race conditions problems with it.
I had similar issues with loosing session id's when there were concurrent requests from same session id. Since file was locked by first request all other concurrent connections were unable to access file and some of them generated new session id. Those situations were also very rare and it took me time to locate the problem. Since then I'm using memcached for session storage and those problems vanished.
It is hard for me to answer this without further information however are you sure this only happens when you have more traffic. What can be done:
Add the codez
OS distro and version
PHP version
Do you have any session checks that rely on the IP. If so it might be that you are actually using a proxy which gives a different IP once every so oftern (like Cloudflare) in which case you can use the HTTP_CF_CONNECTING_IP to get the actually constant IP.
I have also noticed one more thing:
session.use_only_cookies = 1
session.cookie_lifetime = 0
So the cookie will actually be destroyed when the browser closes. Is it possible the connection is lost because the user closes the tab (which in some browsers does actually clear the cookies)?
As others have suggested I would strongely say you move to a DB session. Using a central session store can help in stopping race conditions, it won't stop them completely but it does make it harder. Also if you really get that many session ids you might wanna look into using something other than the built in PHP session id, however the built in hash is extremely unique and has a very low chance of being duplicate so I don't think that's your problem.
Clarification Edit:
If you are using a different proxy to Cloudflare then you will, of course, need to get the HTTP header thart your proxy sets, using Cloudflare is an example.
Here's something I've used. It uses javascript to 'ping' the server on an interval of 10 minutes.
<form method="POST" target="keepalive-target" id="keepalive-form">
<input type="hidden" name="keepalive-count" id="keepalive-count">
</form>
<iframe style="display:none; width:0px; height:0px;" name="keepalive-target"></iframe>
<script>
var kaCount=0;
setInterval(function()
{
document.getElementById("keepalive-count").value=kaCount++
document.getElementById("keepalive-form").submit();
},600000);
</script>
All the provided answers have shown good insight to the question, but I just have to share the solution to my exact problem. I was finally able to reproduce the problem and fix it.
So the system contained two subsystems, let's say admin and client interfaces. The admin was unexpectedly logged out when they logged in as client in another tab and logged out the client interface while being logged in as admin. It was doing this because everything was written to one session with namespaces. What I did is remove the code that kept destroying the session on logout action, and replaced it with session namespace unsetting and replacing with guest session for that namespace that only has access to the login page.
I'm using sessions to store items in a shopping cart. I can create and persist sessions, but with some strange problems:
When I close the tab in Firefox (not the entire browser), the session appears to have been lost. Sometimes it doesn't happen though but usually it does.
Every single time I refresh the page or go to another page, the session ID changes to a new one. I've confirmed this by looking in the cookie with my browser, and also on the server. Also, there are a max of 4 sessions stored on the server at one time. Is all this normal behavior?
The sessions seem to be lost at random intervals...it could be a few minutes or more than an hour.
I just followed the Zend manual but no luck in solving any of this. In the bootstrap I also have Session::start() and Session::rememberMe(). I'm using normal file storage for sessions, just storing in /var/lib/php5 which I think is where Zend framework likes to put it.
Thanks for any direction
If the session data is persisting but the ID is changing then there is a chance there is a call to session_regenerate_id() in there somewhere.
I have run into this before, and you will want to do something like this where you start your session at, for me this is in my Bootstrap.php
if (!empty($_REQUEST['PHPSESSID'])) {
Zend_Session::setId($_REQUEST['PHPSESSID']);
}
Zend_Session::start();
This should solve the issue. When a user has a session, it typically gets passed with every request.
Check your garbage cleanup time for PHP - session.gc_maxlifetime. If it's short, it deletes your session files from under your nose and makes it appear "random".
The default value is 24 minutes (1440 seconds)
This should be set to (or greater than) whatever your cookie lifetime (session.cookie_lifetime) is set for in your application.
Is it possible to configure PHP sessions to never expire? I currently have the default 24 minutes set in php.ini - I could whack this up to a couple of weeks or something like that but I was wondering if I can set them to infinite lifetime?
I want to achieve a similar effect to Stackoverflow's: I never have to log in here. Is this achieved on SO with a never-expiring session or some other means?
Also, as a secondary question: How do the expired session files get cleaned up? If someone creates a session and never returns, which process is cleaning up their expired file?
Normally, what appears to be an everlasting session is two things: a session, which expires pretty soon, and a very long-life cookie containing an auto-login token.
There's a great series of responses on sessions and logging-in contained in this StackOverflow question: The Definitive Guide To Website Authentication
Regarding your question about when sessions are cleaned up, there are several php.ini settings for controlling when the garbage collection for sessions is triggered.
Since PHP both allows and encourages you to create your own session data storage handlers, there is no single correct answer to this question.
Answer to secondary question
Session file cleanup is controlled by the following 3 php.ini settings:
session.gc_probability (default value 1)
session.gc_divisor (default value 100)
session.gc_maxlifetime (specified the age after which the session is considered as garbage)
First 2 settings specify the probability of the garbage collection process being started at session start (before or at the very beginning of your script execution, depending on how you have set things up)
In default configuration there is a 1% probability then that this happens. If it does, then files that are older than maxlifetime are cleaned.
As for your first question - why not write a custom session handler, that stores sessions inside the database (if you have one). That way you can see and control the sessions right from inside the database. Handy :)