I'm storing actively changing data in user sessions, which requires consistency for the user even if they log in with another browser or PC and end up with a new PHP-generated session_id
To counter this issue (and for other reasons) I store a username and session_id data pair in a maintained dedicated database, then after session_start() do something like (simplified):
$saved_sessid=$db->querySingle("SELECT sessid FROM sessions WHERE user = '".$user."'");
if(!empty($saved_sessid)){
session_write_close();//dump newly generated session
session_id($saved_sessid);//apply database-saved session_id
session_start();//launch the already existing user session
}
Would this work as might be expected to make sure a particular user (based on logged in username) only has a particular PHP session or might it cause any unforseen issues, potentially security-related ones? I've been unable to find similar cases or test it reliably enough on my own and could do with some more experienced input
as Xuzrus and nogad commented, essentially answering the "question", your method would work without any added unforeseen consequences, at least none directly. any data stored in the dropped session between session_start() and session_write_close() will of course be lost (i'm guessing you expected that), but the new user instance will then be "shared" with the "saved" session's data, with both "access points" processed in queue by php normally as if simply different pages
if you're using multiple instances of php (multithreading) i'm not sure though, i think php locking the session files in /tmp will make any risk of both clients wanting to use the session at the same time wait in line for ongoing processing to complete, but need confirmation on that
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.
I'm setting up a script that my local pub will use to show users slide shows of images, menus, etc. My URL will accept a key(uuid), from which my script will query the database for the content associated with the key based on a company_id. The site will then just rotate through images via javascript or jquery.
Before serving out the content, I would like to make sure that the session or user is authenticated meaning that there is a valid company_id associated.
I've always used $_SESSION variables for web sessions. Since there will be no real need to time out a session, would there be any flags I can set in php.ini to never time out? Or would it be more beneficial to use cookies for this type of work?
Thanks.
You are probably better off using a cookie to store a login token for the user with a distant expiry date, so they are auto-logged in. Preserving $_SESSION indefinitely would cause session files to pile up on your server wasting resources on the filesystem. Instead, a cookie can hold some token (non-guessable value) that is associated with the user in your database. Basic information can be retrieved from the database then when the user returns.
When you call session_start() the script will try and set a cookie in the users browser containing the session id, there is no need to manually set one holding a "non-guessable value" since that is what the session id is supposed to be anyway.
You can change session.cookie-lifetime in the ini file (maybe even with ini_set()) to prevent the cookie timing out at the end of the session.
Preserving $_SESSION will not cause session files to pile up indefinitely. By keeping the session alive the same file will be re-used over and over again (since it is named after the session id), and PHPs built in session garbage collector will clear up dead sessions anyway.
While in general it is a bad idea to make sessions last forever, since it's your local pub, I doubt anyone is going to try and hijack their session. (and even if they did, all they'd get is what's for sunday lunch, right?) :)
Edit:
You could also periodically regenerate the session id, to add a bit more security.
If PHP session is created before login, there will be one session file created for each request to login page.
The problem is if user makes multiple requests to server through a script then those many session files will be created.
If user wants to attack server,he can send abnormally huge number of requests creating so many session files eating up all the temporary space and making the service unavailable.
I am not sure if this kind of attack is really possible/feasible.
Please share your comments on this and implications if PHP sessions is created before/after successful login.
I think you are misunderstanding session_start()
What happens with session_start is, yes, it will create a file for the individual user. But the next time you call session_start(), it is going to use that same file for that same user because the user has a cookie on their system that tells it what ID to use. In order to have the $_SESSION array available, you must call session_start() on every page.
It is very possible that someone could whip up a scenario like you just described.
In reality, yes, a hacker could always have a robot that clears its cookies after every attempt, make 10,000 requests, and possibly create a disk writing problem, but I really wouldn't worry about it too much, because the files are tiny, much smaller than the script you are writing. You'd have to write a lot more files (on the size of millions or billions) to actually create a problem.
If you really want to see what the effects would be on your server. Write a script that creates files in a directory with the equivalent of 2 paragraphs of text. and put it in a loop for 10,000 files.
If you are then worried about the affects it would have, I suggest implementing a tracker that can see an large amount of hits coming to the site from a single IP address and then either temporarily ban the IP address, or do what Google does and just provide them with a static captcha page that doesn't take many resources to serve.
So, going back to the actual 'question':
I set a session for every single user that ever visits my site, because I use sessions for not only User Authentication, but for tracking other variables on my site. So, I believe that you should set it even if they aren't logged in.
If you're worried about a session fixation attack, think about using session_regenerate_id() function.
once you run the session_start() creates the file.
what you can do as an attack is to create a robot to send separate session id in the cookie, but just have to give that one exists.
It doesn't matter, really. Your server, as cheap as it could be, will have enough space to store millions of (almost empty) session files.
Worst it can do is slow down the files access in the folder where session files are stored, but your server's disks should be monitored to begin with, and a quickly filling /tmp partition should raise an alert at some point.
I'm making a php web application which stores user specific information that is not shared with other users.
Would it be a good idea to store some of this information in the $_SESSION variable for caching? For example: cache a list of categories the user has created for their account.
This would be an appropriate use of the session mechanism as long as you keep this in mind:
Session does not persist for an indefinite amount of time.
When pulling from session, ensure you actually got a result (ASP.NET will return NULL if the Session has expired/cleared)
Server restarts may wipe the session cache.
Do this for convenience, not performance. For high-performance caching, choose an appropriate mechanism (i.e. memcached)
A good usage pattern would be like this (ether cookies or session):
User logs in
Store preferences (background color, last 10 records looked at, categories) in session/cookie.
On rendering of a page, refer to the Session/Cookie values (ensuring they are valid values and not null).
Things not to do in a cookie
Don't store anything sensitive (use session).
A cookie value should not grant/deny you access to anything (use session).
Trap errors, assume flags and strings may not be what you expect, may be missing, may be changed in transit.
I'm sure there is other things to consider too, but this is just off the top of my head here.
That could work well for relatively small amounts of data but you'll have to take some things into consideration:
$_SESSION is stored somewhere between requests, file on disk or database or something else depending on what you choose to use (default to file)
$_SESSION is local to a single user on a single machine.
sessions have a TTL (time to live), they dissapear after a set amount of time (which you control)
Under certain circumstances, sessions can block (rarely an issue, but i've run into it streaming flash)
If the data you mean to cache is to be accessed by multiple users you're quickly better off caching it seperately.
If you only want this data available during their session, then yes. If you want it available tomorrow, or 4 hours from now, you need to save it to a database.
Technically you can modify the sessions to have a very long lifespan, but realize if they use a different computer, a different browser or flush their cookies they will loose the link to their session, therefore anything serious you should create a type of user account in your application, link the session to their account and save the data in a permeate place.
I am attempting to integrate an existing payment platform into my webshop. After making a succesful transaction, the payment platform sends a request to an URL in my application with the transaction ID included in the query parameters.
However, I need to do some post-processing like sending an order confirmation, etc. In order to do this, I'd need access to the user's session, since a lot of order-related information is stored there. To do this, I include the session_id in the intial request XML and do the following after the transaction is complete:
$sessionId = 'foo'; // the sessionId is succesfully retrieved from the XML response
session_id($sessionId);
session_start();
The above code works fine, but $_SESSION is still empty. Am I overlooking something or this simply not possible?
EDIT:
Thanks for all the answers. The problem has not been solved yet. As said, the strange thing is that I can succesfully start a new session using the session_id that belongs to the user that placed the order. Any other ideas?
Not really what you ask for, but don't you need to persist the order into database before you send the customer to the payment-service? It's better to rely on persisted data in your post-processing of the order when you receive the confirmation of the payment.
Relying on sessions is not reliable since you will have no idea on how long this confirmation will take (usually it's instant, but in rare cases this will have a delay).
Also, in the event of your webserver restarting during this time span, will make you lose relevant data.
A third issue is if you have a load-balancing solution, with individual session-managment (very common) then you will have no guarantee that the payment-server and your client will reach the same webserver (since stickiness is usually source-ip based).
I will venture to guess that since domains are different from where the session is set to where you are trying to read it, php is playing it safe and not retrieving session data set by a different domain. It does so in an effort to preserve security in case somebody were to guess session ID and hijack the data.
Workaround for this, assuming the exchange happens on the same physical disk, is to temporary write order data to a serialized (and possibly encrypted depending on wether or not full credit card number is being tracked, which is a whole another story) file that once read by the receiving end is promptly removed.
In essence all that does is duplicates the functionality that you are trying to get out of sessions without annoying security side-effects.
Many thanks for all the replies.
Smazurov's answer got me thinking and made me overlook my PHP configuration once more.
PHP's default behaviour is not to encrypt the session-related data, which should make it possible to read out the session data after restarting an old session from another client. However, I use Suhosin to patch and prevent some security issues. Suhosin's default behaviour is to encrypt session data based on the User Agent, making it a lot harder to read out other people's sessions.
This was also the cause of my problems; disabling this behaviour has solved the issue.
Make sure you're closing the current session before you attempt to start the new one. So you should be doing:
$id = 'abc123';
session_write_close();
session_id($id);
session_start();
Dirty, but has worked for me:
Tell the payment gateway to use
http://yourdomain.com/callbackurl.php?PHPSESSID=SESSIONIDHERE
PHP uses that method of passing a session around itself if you set certain config vars (session.use_trans_sid), and it seems to work even if PHP has been told not to do that. Its certainly always worked for me.
Edit:
Your problem may be that you have session.auto_start set to true - so the session is starting automatically using whatever ID it generates, before your code runs.
How about do it in another PHP page, and you do a iframe include / redirect user to the second page?
I'm not sure the exact length of time between your transaction and your check; but it certainly seems that your session cookie has expired. Sessions expire usually after 45 minutes or so by default. This is to free up more uniqid's for php to use and prevent potential session hijacking.
I'm not sure if you have a custom session handler and whether it's stored in the database but guessing from your posts and comments on this page I would assume it is stored in server side cookies.
Now the solution to your problem, would be to bite the bullet and store the necessary data in the database and access it via the session id, even if it means creating another table to sit along side your orders table.
If however you are doing the action immediately then the other explanation is that either the user logged out or committed an action which destroyed their session (removing the server side cookie).
You will see these cookies in your servers /tmp folder, try have a look for your cookie, it should be named 'sess' + $session_id.