I am using codeigniter's session class to handle my PHP sessions. One of the session variables automatically created on every visit to the site is session_id:
The user's unique Session ID (this is a statistically random string with very strong entropy, hashed with MD5 for portability, and regenerated (by default) every five minutes)
On my site I need to have functionality to track unregistered user's and I currently have this implemented by comparing the visitor's session_id with a stored id value in a VISITOR table in the database. This works perfectly except for the fact that the session id times out every five minutes. I would like my application to remember visitors for longer than 5 minutes (kind of like what SO does when you post a question or answer without registering).
My question is this: can you see any security issues with simply extending the regeneration time of the session class (to something like 12 hours)?
Update: based on the answers I've seen so far, it seems like its more of a performance concern rather than a safety issue. Its kinda weird how the codeigniter session class works because when creating a new session, it also creates a new cookie which seems to persist as long as the session. I guess I could create another cookie with the session ID that lasts as long as I need it to. But how much of a performance concern would it be if I were to save the sessions for something like 12 hours? Would it slow things down unless I have millions of unique visitors within a 12 hour period (in which case I'd have bigger problems to worry about...)?
Two things with that idea :
If users go away from their computer (without locking it / closing their browser), someone else might use it to go to your site with their account
well, that's probably not your problem
if you have some login/password fields, your users probably already have their login+password memorized by the browser anyway (well, for the registedred ones, anyway -- and those probably have more "power" than not registered ones)
If you have lots of users on your site, you will have more session files
as sessions are stored in files
(same if they are stored in DB / memcached -- in which case you must ensure you have configured memcached so there is enough RAM to store more sessions)
So, yes, there is a small security risk ; but I don't think it is really relevant.
Another idea would be to keep a short session lifetime, but to store some informations in cookies, with a lifetime more important than that ?
Enough information, actually, to allow re-creation of a new session, without the user noticing anything ?
But, yes, that would require a bit more work on your side...
To add a bit more precisions after your edit :
Its kinda weird how the codeigniter
session class works because when
creating a new session, it also
creates a new cookie which seems to
persist as long as the session.
This is the "standard" way of dealing with sessions -- at least, in PHP :
The session's data is stored in a file, on disk, on the server
and a cookie is used to keep a "link" between a user, and the file containing his session's information. Without that cookie, there would be no way of knowing which one of those files contains the session of a specific user.
But how much of a performance concern
would it be if I were to save the
sessions for something like 12 hours?
If you're having millions of users on your site, this will means having millions of files, each one containing the session's data of one user -- and it's not good to have too many files.
But is you are having a few hundreds user, that should be allright, I guess.
Depending on the amount of visitors to your site, saving sessions for 12 hours may not be a good idea. Why not use cookies? This is dependent on whether or not the user has it enabled in his browser though: http://www.php.net/setcookie.
One Security Tip:
Leave True on sess_match_useragent(application/config/config.php)
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 know there are hundreds of these questions but what I am asking however is slightly different.
When the user logs in I would like to get all their data from each table in a database and store it in a session variable (obviously not sensative data such as encrypted password/salts etc basically data that would be useless or have no value to a hacker!!), and whilst the user uses the website the relevant data stored in the session will be used as opposed to accessing the database everytime. Moreover when the data is changed or added this will be written or added to the session file, and upon a major action such as "saving" or "loggin out" the new/changed data will be written to the database.
The reason I wish to do this is simply for efficieny, I want my application to not only be fast but less resource consuming. I am no expert on either which may explain why my idea makes no differnece or is more resource intensive.
If there is an alternative to my solution please let me know or if there is something to improve on my solution I will be glad to hear it.
Thank you.
My application is using PHP and mysql.
If any of these don't apply to your app, then please ignore. In general, I'm against using sessions as caches (especially if anything in the session is going to be written back to the DB). Here's why.
Editing the session requires a request from the user. Editing a php session outside of the request-response cycle is very difficult. So if a user Alice makes a change which affects Bob, you have no way to dirty Bob's cache
You can't assume users will log out. They may just leave so you have to deal with saving info if the session times out. Again, this is difficult outside of the request-response cycle and you can't exactly leave session files lying around forever until the user comes back (php will gc them by default)
If the user requires authentication, you're storing private information in the session. Some users may not be happy about that. More importantly, a hacker could imploy that private information to conduct a social engineering attack against the end-user.
Mallory (a hacker) might not be able to use the information you put in the session, but she can poison it (ie. cache poisoning), thereby causing all sorts of problems when you write your cache to your permanent storage. Sessions are easier to poison then something like redis or memcache.
TL;DR Lots of considerations when using a session cache. My recommendation is redis/memcache.
You can also go for local-storage in HTML5, check The Guide and THE PAST, PRESENT & FUTURE OF LOCAL STORAGE FOR WEB APPLICATIONS
Local Storage in HTML5 actually uses your browsers sqlite database that works as cookies but it stores data permanently to your browser
unless someone by force remove the data from the browser finding the data files
Or if someone remove/uninstall browser completely,
or if someone uses the application in private/incognito mode of the browser,
What you need to do
Copy the schema for required tables and for required columns and update data at a regular interval
you dont have to worry about user's state, you only have to update the complete data from the localStorage to mysql Server (and from the mysql server to localStorage if required) every time user backs to your application and keep updating the data at regular interval
Now this is turning out to be more of localStorage but I think this is one of the best solution available for me.
redis is a good solution if it is available for you (sometimes developers can't install external modules for some reason) what I would do is either go with your Session approach but with encoded/encrypted and serialized data. Or, which I really prefer is to use HTML5 data properties such as:
<someElement id="someId" data-x="HiX" data-y="Hi-Y" />
which BTW works fine with all browsers even with IE6 but with some tweaks, specially if your application uses jquery and ajax. this would really be handful.
You need to use Memcache for this kind of work. To solve the problem of keeping the updated data everywhere you can create functions for fetching the data, for example when the user logs in you, authenticate the user and after that insert all the user data into the memcache with unique keys like :-
USER_ID_USERNAME for user's username
USER_ID_NAME for user's name
etc...
Now create some more functions to fetch all this data whenever you need it. For ex
function getName($user_id){
if(Memcache::get($user_id."_name"){
return Memcache::get($user_id."_name");
} else {
//Call another function which will fetch the data from the DB and store it in the cache
}
}
You will need to create functions to fetch every kind of data related to the user. And as you said you want to update this data on some major event. You can try updating the data using CRON or something like that, because as tazer84 mentioned users may never log out.
I also use what the OP described to avoid calls to db. For example, when a user logs-in, i have a "welcome-tip" on their control panel like
Welcome, <USERS NAME HERE>
If i stored only his user_id on $_SESSION then in every pageview i would have to retrieve his information from the database just to have his name available, like SELECT user_name FROM users WHERE user_id = $_SESSION['user']['user_id'] So to avoid this, i store some of his information in $_SESSION.
Be careful! When there is a change on data, you must modify the data in db and if successfull also modify the $_SESSION.
In my example, when a user edits his name (which i also store in $_SESSION so i can use it to welcome-tip), i do something like:
If (UpdateCurrentUserData($new_data)) // this is the function that modifies the db
{
$_SESSION['user']['user_name']=$new_data['user_name']; // update session also!
}
Attention to:
session.gc_maxlifetime in your php.ini
This value says how much time the $_SESSION is protected from being erased by the garbage collector (the file that exists on your disk in which the $_SESSION data are stored)
If you set this very low, users may start getting logged-out unexpectedly if they are idle more than this amount of time because garbage collector will delete their session file too quickly
if you set this very high, you may end up with lots of unused $_SESSION files of users that have left your website a long time ago.
also i must add that gc_maxlifetime works together with session.gc_probability where in general you need lower probability for high-traffic websites and bigger probability for lower traffic since for each pageview there is a session.gc_probability that garbage collector will be activated.
A nice more detailed explanation here http://www.appnovation.com/blog/session-garbage-collection-php
I know this sounds stupid but ....
If ur data is not sensitive the best way to make it accessible faster is to store it in hidden variables inside the forms itself. You can save comma separated or values in an array.
So let's say user did something on my website, for example uploaded some images or whatever, and he left without logging out and never came back or let's say he did come back after few months.
So my question would be, is there some kind of way for example to delete his uploaded files after session have expired, let's say after 30 mins (keep in mind that user never reloaded page), so that would need to run entirely on server side without user interfering at all.
EDIT Thank you all for your wonderful answers, it gave me quite a few great ideas, i wish i could accept all of your answers :)
Good question! My first idea was to use a database based solution. If you don't already, you'd keep track of all active sessions in a table sessions which contains, among other things you may need, the session_id and the last_visited_time. This entry would be updated every time a user visits your site:
UPDATE sessions WHERE session_id = "<current session id>" SET last_visited_time = NOW()
The second part of the mechanism would be a cronjob that scans the the sessions table for sessions whose last_visisted_time hasn't been updated lately (in whatever time interval you'd like) and deletes the files for that session.
One way would be to call
$thePath = session_save_path();
and iterate over all saved session file, unserialze each and check them for the specified timeout property.
Unfortunately, you need to scan the whole directory to find all session files, which are older than a defined period of time. You'd use start() to figure out the age of a session file.
On a well-maintained server, each virtual host should have a separate directory for its session data. A not-so-well-maintained might store all sessions in a unified shared directory. Therefore, ensure that you don't read or delete other virtual hosts' session data.
Better Approach using a database
Therefore I propose to save session data to your application's backend database. Using SQL, it would be trivial to find all outdated session files.
The documentation for session_set_save_handler() provides a sample, which explains this whole process quite nicely based on objects.
I like all the answers above, but a different solution would be to name the uploaded files in a way that you know they are "temporary", for example prepending their name with a timestamp. This way, a periodic process would clean any such files, unless your program decides that they should be kept after all, renaming them accordingly.
I've got a php application and I'm saving the session variables for the user using $_SESSION itself. Is there any particular advantage of storing it in a database?
I'm looking for a reliable / well-researched article which talks more about this. I havent been able to locate anything yet.
The advantage you have of storing it in a database is that the data exists as long as you want it to exist.
Your browser will destroy the session according to how it is setup, which makes it a bit unreliable. I can't however find an article on this yet but this is what I use as a convention for a situation like this.
Any data that needs to be stored long term, like user details and activity I store in a database. Any data that is only relevant to the current workspace, like logging into a site and posting a few comments etc. can be stored in the session. For instance I store user authentication details in a session to constantly check whether the user is logged in or not and whether to redirect him/her to the correct page.
This works wonders when checking access rights throughout your application.
For me its much safer to store user details in a database because it cannot be publically accessed like the $_SESSION.
Please disagree with me if you want to though.
I would say storing in database is better.Because
When you are hosting your site with a shared host
PHP uses the same path for storing sessions for all the users,somewhere that is not in your folders.
You can track the users and their status easily.
For application that are running on multiple servers, you can store
all the session data in one database.
This article may help.
Well this is a question for the ages. Personally from what I have learned in my time. Unless your site starts booming on a massively large scale where you need to start using multiple servers for various aspects of the system such as load balancing where you have many mirror systems running. Or need to improve performance a little for an over populated system the benefits of using DB related sessions or File based sessions really isn't any different.. Grant it I could be wrong this is merely my own personal perception off my own experiences. Just like you Ive never really found any articles, posts, other that really put either to the test side by side hell I don't even think I have found anything that really puts either to the test stand alone for that matter. Personally I just go with what ever the need is (or desire of my client) usually I just stick to native sessions file based.
I hear they can be spoofed, but have seen no proof to that notion to date. So other than that potential I stick with file based. Unless I am using a system like code igniter then sessions seem to handle better DB driven with it rather than not.
At some point in time you're going to have to store something in a session. Whether it's all the session variables or just the ID of a row in a sessions table. That being the case it would be fairly easy to alter the ID stored in a badly encrypted session and hijack a different session.
Consider this:
Full Session Option. This has the User ID, Username and an encrypted and hashed password stored so that every time a page is called it verifies my login. To hijack someone else's session I'd have to know their User ID, Username and Password Hash and be able to overcome the sessions inherent encryption.
Session + DB Option. This just has a Session ID stored that references a row in a database. All I have to do to change the session I want is to break the encryption on the session and say add one to the Session ID. I'd then be authenticated as the user that logged in after me.
You could store login details in a session and then any none login related data in a session table if you have a lot of extra information but then again you might as well just remove the need for an extra table and extract the data from whatever relevant tables you need.
From my short experience, you should store in $_SESSION only data that you will NOT need to be refreshed in all sessions opened by a unique user in different devices.
(mobile/desktop/etc.)
In other words, data that you are sure will never change like a userID.
For example, I had stored the user profile picture path into
$_SESSION and it led to a strange User Experience. When changing the
profile picture in a desktop, it did not refresh the profile picture
for the user on his mobile. Other users saw the new picture though.
Indeed, the path was refreshed into the DB but not in the $_SESSION.
Login-out and Login-in would not change anything.
Remember that the default behavior is that $_SESSION passed with cookie will be different for each browser even if this is the same user logged in. You will have to do a session_destroy() to avoid being stuck with old data.
Very temporary data may be stored in $_SESSION as well I guess.
NB: the basic need of global session, out of these arguments, is to have variables available globally
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.