I have a small situation here but I wanted to try and be sure I was approaching this in a correct way.
I have a web application that is used by several shops.
Each shop is authenticated through htaccess and htpasswd in order to connect to the correct database.
This portion works great!
Each shop has multiple employees but each employee uses a separate computer/workstation.
So it goes Shop logs in, gets authenticated, connects to proper database and then loads a login page.
At the login page the user logs into the application using name and password, and they are good to go.
At this point I am loading user information (UserID, Security Level, etc) into the session.
Part of my problem is trash collection as every once in awhile the session variables are getting lost.
Every page has session start as the first thing so I imagine after an hour or so of inactivity the session is getting collected by the trash collector and poof, it is gone.
I am toying with the idea of loading the user information into the $GLOBALS supervariable to avoid losing the session due to inactivity.
Now, I realize that there are ways to delay/stop the trash collector in PHP but it seems to me if I use the global scope it removes the need for extra coding or configuring of PHP.
Am I correct in assuming that as long as each user is on their own machine accessing the site that using the $GLOBALS will only apply to each user?
Think you have a general misconception of session and global variables.
Global variables are the variables which remain common for the whole
application… Their value can be used across the whole application
whereas Session variables are variables which remain common for the
whole application but for one particular user. They also can be used
across the whole application… But they die when a particular user
session ends.
https://stackoverflow.com/a/14848246/1022914
I recommend using sessions though. Check the user details against user data stored in a database. If it passes authentication, create session variables with user data to be used across your pages. This makes thing a whole lot easier
You can use cache . It can help u to keep user logged in always , as facebook .
Related
I am experiencing a race condition when 2 users (almost) simultaneously access the same page. This causes the user to gain access to another users data.
I have been trying to catch this issue for some months and have finally managed to do so.
I am using Yii Framework 1.1 and the user login process is as follows:
Sessions are stored in the database, I dont actually use $_SESSION to store anything.
A generated Session ID is stored in a cookie and populates $_COOKIE which is used by PHP to connect the user to their data.
From the login page, I store the Session ID from the cookie in a field of the form.
The user logs in, input is validated, Session Data is created and stored with the user record, including the Session id from the form (the real Session ID). The user is then routed through 2 more controllers (LoginCheck, Dashboard) to land on the Dashboard.
During a session, the user will frequently return to the dashboard.
When 2 or more users access the dashboard page (almost) simultaneously (via login or returning from a page within the site), both users will end up with the same cookie id and session data. I can confirm this by checking the browser based cookie with the cookie value stored in the $_COOKIE variable. A simple refresh of the dashboard on the page with the incorrect data results in the correct data being loaded.
I have researched race conditions with sessions in PHP and some of these offer the use of $_COOKIE to resolve race conditions with sessions so not really providing me with any solutions to my problem.
As I am able to trap the issue, I can easily resolve it with a refresh, but if there is a more stable solution available I would prefer to go down that route.
Any advice would be greatly appreciated.
Cheers
You can use a fopen with x or x+ flag to a shared file. Only one of the instances can open the file simultaneously.
However what you describe is inconsistent and weird: you should not need to deal with race conditions while using sessions as you describe. I guess that the problem is that you regenerate the session id on each page load, so you are probably doing something you shouldn't.
On sessions each user agent must generate a session id only once, but as you describe that id is regenerated on each page change, and as a secondary problem it's generated with low entropy.
If you fix the first problem, then the low entropy problem will be mitigated, but not solved.
Difficult to explain this but here goes. I found a similar question in the search but it was for C, not PHP.
I am developing a PHP site which has two logged-in sections, one for employees and one for employers. When either user logs out, their session is cleared, at the moment with "session_destroy()". I also use that at the login page to clear any previous session.
The problem comes if I am working on both sections at the same time. Because they are on the same "site", logging into one logs out of the other. I am forced to use two browsers at a time, one logged into one section and the other into the other.
Is there a better way to end a session when a user logs out rather than "session_destroy()", something that won't affect the other part of the site?
you can save each site's session data in a different part of the session:
$_SESSION['site1'] = ... ;
$_SESSION['site2'] = ... ;
and then call unset on the session you don't want any more:
unset($_SESSION['site1']);
you unset a specific session
unset($_SESSION['variable']);
variable will be the user/admin session value
Sorry for the newbie question! I'm making a small website that allows users to create their own accounts. It's not a banking system, and it's unlikely that someone would want to hack it. That said, I am trying to make it reasonably secure, as there are plenty of bored script kiddies out there.
Could someone describe a basic workflow for a user logging in and having a cookie set that will keep them logged in for 30 days?
At the moment I have the following:
Validate and sanitize inputted data.
Check supplied credentials against bcrypt hashed password in DB.
If correct then call "Login" function.
Login function:
a. Delete any session data from DB with userID (table with two columns: SessionString and UserID).
b. Add new session data to DB (newy random generated string and UserID).
c. Write random generated string and UserID to cookie.
d. Set $_SESSION("UserID") with $userID.
But although the two cookies are being created and written to, the $_SESSION("UserID") remains blank... I'm guessing because I can't write to $_SESSION any time I like?
And even once that's fixed, how do I use the data stored in the cookie to log a user in? I'm guessing I don't want to go to the DB on every page load. And it will still require me to create a database object to see if the credentials in the cookie are ok. Is this the right way to this?
Once again, apologies for the newbie question!
UPDATE:
Yes, I do understand the difference between $_SESSION variables and a cookies. I also have session_start() at the top of every page (right after <php with no blank lines). $_SESSION("UserID") just remains blank.
Here's the code from the top of the page:
<?php
session_start();
if(!isset($_SESSION['initiated'])) {
session_regenerate_id();
$_SESSION['initiated'] = true;
}
Thanks for the help.
First off, there is an important difference between a session and a cookie. When you use the $_SESSION[".."] you are creating a session (which lives on the server, compared to a cookie which lives on the client), even though the browser uses a cookie to keep track of the session id. To create a cookie you would use the setcookie() method.
That said, I would recommend you to read through this article which is a step-by-step guide on how to create a secure login script, with persistence using a cookie for a "Remember me"-feature. Describe how to do it in detail would be to extensive for an SO answer im afraid.
Side note:
To be able to write to the session, you might have to call session_start(); prior to getting or setting a session variable using $_SESSION[".."].
Did you write a custom session handler that has your session-files stored in the db? I guess you don't.
If you want to use $_SESSION you have to also do session_start(). When using PHP sessions the cookie to identify the user will be set for you. You will also get session files created in your /tmp directory. That's the location your variables and anything you assign to $_SESSION will be stored.
Unless you define a custom session handler, that will manage the location of the session files, you won't need to query your database. Just save the users credentials in $_SESSION.
See this Tutorial on how to use PHP sessions.
PS: You access arrays like this: $_SESSION["UserID"], not with ().
you might want want to look at this article in which i have already discussed about various types of session hijacking and how you could avoid it.
session security in php
I am looking for insights into how to destroy a specific session in PHP. Through a partner website a user logs into the main website using a token and obtains a full session.
It is also possible for the partner website to call a destroy function if the user logouts from the partner website. We should then also log out our own user.
What is the best approach to this? The Zend_Session destroy method does not accept a parameter, similarly the PHP function session_destroy does neither.
I am considering two options:
Removing the session information directly from file/memcache but would prefer a "cleaner" approach than this.
Checking at every page request if this is a "token" user ; and if then check if their token was expired by maintaining a list. This adds overhead to a busy website, but might be my only option.
Or is there a third / better approach I am not seeing?
There's no need to roll-your-own session handling.
session_id() can take a parameter, the session id you want to work with.
So, when you pass the user off to the partner site, pass along their session_id (or some token, or whatever).
Then allow the partner site to hit a script like this:
kill-user-session.php
<?php
/**
* Destroy any active session identified by $_POST['sid']
*/
session_id($_POST['sid']);
session_start(); //this line may not even be necessary
session_destroy(); //destroys that session.
So when the user logs out on the partner site, the partner site POSTs the session_id (that you gave them) to your kill-user-session script, and the user's session is destroyed on your server.
Of course, you probably want to limit access to kill-user-session.php via some method or another.
If you wish to be able to 'kick' the sessions of a user(s), the only way you can do it is if you use MySQL (or someother db, sqlite even) for your session storage.
Then you can simply remove entries from the db to kill a session.
This also allows you do do things such as, 'take control' of a specific user's session and other stuff :)
See this for a very basic run through: http://www.devshed.com/c/a/MySQL/Custom-Session-Management-Using-PHP-and-MySQL/ (not the best example but good enough full example to start you).
EDIT
Also, if logging out through the partner site, another method I have used in the past (which was with O2 and other such sites) they were given a 'callback' (REST API call in most cases) which they would also need to call when the user logs out of their site.
The database solution means that the session database needs to be shared between mainwebsite and the partner site, which frequently isn't the case etc. Maybe something along these trivial lines would suffice?
<img src="mainwebsite/logout.php">
mainwebsite/logout.php:
<?php session_destroy(); ?>
I'm working a site where users could technically stay logged in forever, as long as they never close their browser (and therefore never get a new session key). Here's what I could see happening: a user leaves a browser open on computer A. The then use computer B, login and change their name which is stored in the session. They logout of B, but A is still logged in and still has their old name stored in the session. Therefore, their name won't be updated till the next time they logout manually or they close their browser and open it again and are logged in through the remember me function.
Name is a simple example, but in my case the subscription level of their account is stored in the session and can be changed.
How do you deal with this?
A few ideas that I have are:
After a period of 10 minutes or more, the session data get's reloaded. It might be exactly 10 minutes if the user is highly active as the function will get triggered right at the 10 minute point or it could be after 2 hours if the user leaves and comes back and then triggers the functionality.
Store as little information as possible in the session and load the rest from the DB on every page call. (I really don't like this idea.)
Use database sessions and use the same session on all the computers. I like this, but I could see it getting confusing when something like search criteria are stored in the session--the same criteria would show up on both browsers/comptuers.
For information, even such as the user's name or username/email address, store it in the session, but for other information that would heavily affect their abilities on the site, don't store it in the session and load when needed (attempt to only do it once per instance).
Are there other better methods?
--
Another option: 5. Use database session and when an update is made load the user's other sessions (just unserialize), change the relevant information and save them back to the database.
I would go either with number 1 or number 4. If you store the time of the last update of the information, you could even ask on every request whether the date has been updated.
Don't store information likely to change in the session, if you're looking at scenarios like the one you outline. Just get over your dislike of loading user data with every page - it's by far the best idea.
I'm guessing you don't want to load the data from the database because you're concerned about performance issues somehow. Before you try out any of the other solutions, you might want to test how long it takes to actually load a users data from the database, then check that against your number of users - chances are you won't see any performance problems due to loading user profiles on every page.
Regards
I'd go with option 6: only store userid and session specific stuff (search criteria) in his session and put the rest into APC/xcache (memcached if you're using multiple servers).
this way you'll only have to go to the database the first time (and after the cache expires) and you can still share any data between users sessions.
Normally you should do 2), but you don't like it.
maybe you can use sessions stored in db.
when a user change his name, put into all sessions from that user the information "refresh userdata".
on the next request the userdata is reloaded again into the session and is cached there.
this can be done be reusing your loaduserdata function which called at login.
php session_set_save_handler() - also read comments
php session_decode() - to read the username from the session to store it additionally to the sessiondata. usefull for easily to find the users sessions for updating.
[edit]
don't forget:
when you are updating all the sessions while the page is generated (between session_start and session_write_close) you changes maybe lost.