How do I properly separate environment using sessions? - php

I got a situation here in my software, that can bring me a lot of headaches. I'll try to explain the best I can.
I have 3 environment actually, all 3 environment use the same register, log in and recovery system. But each one of them are properly separated, let say the structure is:
Admin/
Store/
Supplier/
The structure above contains a Register, Log In and Recovery methods in a class but the code is the same. I know it would be made all together and create some identification code to separate them, but the software was not planed to grow like this, and now we got a situation. ;(
I first got the problem when I was logged into Admin account for instance, and try to access the Store/ environment (account) without any session (but of course the session used was the admin account). I got the access and it is not safe if one supplier know about the problem or customers of the Store know about this.
What should I do to prevent this type of problem? Re-Write the code? or are there some workaround that I can write into my session code?
Thanks!

You can use session_name() to define which cookie name is used to store the session ID, this way you can name and separate the different environments under the same Host. Use it before calling session_start().
For instance, every session_start() call in the Admin area should preceed with:
session_name("ADMINSESSID");
session_start();
And you do similar things to Store and Supplier.
Although it works to separate $_SESSION environments, I'm not totally sure about the security aspect of it (for instance editing Cookies to use the Supplier session ID as an Admin session ID). Perhaps you should also mark in each $_SESSION which environment it belong to.
At login time:
// if user authenticated successfully to that environemnt
$_SESSION['environment'] = session_name();
Anywhere else in the same site area:
if ($_SESSION['environment'] != session_name())
die('Access violation.');

Related

Should I use Session variables or the global supervariable

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 .

laravel and multi-sessions from the same browser

In our web app, If I use a single browser, login to our application as user A, open another tab and login as user B - User A loses his session data. I assume this is due to a shared cookie made out with the user-agent. Is there a way to concat its name with a username? so that sessions can co-exist between concurrent logged in users using the same browser on the same machine?
We use Laravel 5. Is there any way around it?
Laravel Session Background
Sessions
Skip this section for a quick easy solution
In Laravel, session cookies are created via the Illuminate\Session\SessionManager class, namely through the buildSession method:
SessionManager::buildSession
protected function buildSession($handler)
{
if ($this->app['config']['session.encrypt']) {
return new EncryptedStore(
$this->app['config']['session.cookie'], $handler, $this->app['encrypter']
);
} else {
return new Store($this->app['config']['session.cookie'], $handler);
}
}
In this method we can clearly see that the name of the session comes from our config\session.php, looking in particular this line:
session.php
'cookie' => 'laravel_session', # ~~ ln 121 at time of writing
Ok, but that doesn't help a lot, changing this, changes it everywhere, as noted by the comment proceeding it in the config.
The name specified here will get used every time a new session cookie
is created by the framework for every driver.
And even if we could pass it some dynamic value, something like:
'cookie' => 'laravel_session' . user()->id,
This creates a paradoxical, time ending, universe imploding outcome because you are requesting the id from the user which is accessed via the session looked up by the cookie name laravel_session.. (mindblown)
Let's leave SessionManager and it's session.php configuration alone. We can see from above that regardless of how we approach this, all our session info will be fall under that single laravel_session key.
Guard
Maybe Guard will have some more information.
Guard is your key to auth into your app, and one of the many things that makes Laravel awesome for quickly creating applications.
The method to look at is Guard::user().
One of the first things Guard::user() does after some initial cache and logged out checking, is a session check.
Guard::user()
$id = $this->session->get($this->getName());
So here, Laravel is fetching the session values that match the result of getName() - awesome - all we need to do is mod getName() to return a value, let's take a took at that method:
Guard::getName()
public function getName()
{
return 'login_'.md5(get_class($this));
}
That's pretty straight forward. $this refers to the Guard class, so the md5 will effectively always be the same (if anyone knows the 'why' behind md5'ing the class name which would be the same each time, leave a comment).
There are a few places where this should be updated, such as getRecallerName.
So from here, you can extend the core Guard class and splice in your getName and getRecallerName methods.
You will probably want to wrap some service provider around this, write some unit tests, possibly even overwrite the original auth manager.
"Geez, that seems like a lot of work"
"It sure is Billy, it sure is"
https://www.youtube.com/watch?v=dTxQ9yhGnAg
See the next part
The quick "I just need an answer" answer
Ollie Read has already created a solution, found here:
https://github.com/ollieread/multiauth
I encourage you to have a look, especially the custom Guard class which extends core Guard with custom getName methods.
Any major browser will only store one session cookie for a site, but the site developer gets to choose what's in that cookie. It seems like your site is storing user information in the session cookie, which is then getting overwritten when the other tab stores different information in the same cookie.
You don't provide much detail about how your specific site operates, but here are a few general ways of approaching this problem.
1) Use different browsers for different users. Different browsers don't share cookies between them. If your goal is simply to test your site with multiple users, this is the way. You can also use Incognito/Private mode to log in a separate user, as this mode doesn't share cookies either.
2) Don't use session cookies to store user information. This is a non-starter on most websites, but if this is an internal site or strictly controlled environment, you may be able to pass user identification via the URL, POST data, or some other hidden identifier in the request.
3) Store data in the session cookie for all currently logged in users. Depending on the web framework, it may be possible to create a map of user -> cookieData and look up the correct one based on which user is making the request. This is an advanced technique, and I don't actually know if Laravel exposes this level of control.
Multi userlogin with same browser like google add account. for that you need follow some steps and re-write auth library which provided by the Laravel,
Steps
Tack backup of your Auth file.
Change all session store functionality to store it first in array and then store that array to session
Now you need to create the new session variable which will store the current user instance id like user 0 1 2 ...
Now you need to change all the function from you will get the values from the session you need to check if the session object is empty then user is logout else you need to get data of the user base on the user instance.
You need to change your instance when user want to switch from one account to another.
The easiest is just a URL based sessionID which could be a security issue depending on how your application is designed, especially when sharing urls with non-expired sessions.
Since L5 doesn't support php native sessions anymore, you'll have to use a custom provider like below:
This will use sessionID in the url for laravel V5:
https://github.com/iMi-digital/laravel-transsid
Basically the session is URL based, so you can just login in a different tab and get a new sessionID, and that person can easily do a "open page in new tab" to have two pages of the same user if needed as well.
The library above locks the session to the IP and User Agent so link sharing won't accidentally leak a session.
tl;dr: Yagni
Consider a person (http client in your case) with 2 identities: Dr Jekyll and Mr Hyde.
He visits his new friend Sir RM1970 (http server in your case): "How do you do, RM1970!".
Here is the problem. Poor RM1970 need to welcome back the monster, and there are few options:
fall deep into this rabbit hole: "How do you do both Dr Jekyll and Mr Hyde!", which incredibly complicates further conversation (your ACl, for example, will need to operate with list of identities, and make a decision about priorities if they conflict realtime)
make a decision on your own: "How do you do Dr Jekyll!" and pray you made the right choice (randomly pick user's identity and bring your users some fun with unpredictable responses)
be sly and shift this responsibility back to him: "Pardon me? Who are you? Name yourself!" (require single identity per request)
The later is how it actually works. The browser provides the latest confirmed identity.
You've been asked to change this, but do you really want it? Hold the line and don't accept this responsibility.
If you are not going with first 2 dead-end options, you will need to ask user on which behalf he sends the request. The best option here is to make your frontend stateful, maintain list of opened sessions, and provide a UI for user to pick one. It is almost the 3rd Ryan Bemrose's option, but store this data on client side, and send only the chosen one. No changes in laravel backend required.
The problem here is switching tabs will not automatically switch user, and will be rather confusing, providing very little difference with logout/login path, which is already implemented.
Some browsers support multiple profiles (example), which may be an acceptable alternative. Basically it is the same as 1st Ryan Bemrose's option, but does not require multiple browsers installed, and can benefit from permanent cookies, aka 'remember-me'.
I don't exactly know what do you need this for, but as a developer I sometimes have to log into an application with multiple users. To do that I usually use incognito mode or if its more than 2 users I had some luck using this extension in chrome.
I know its not an answer to your question but it just might be what your looking for.
Different seesions coexist between concurrent logged in users cannot just only implemented by session cookie,because cookie is stored by browser. So the logged
in user's seesion must be stored by Server.
As all we know, Once session_start is called,SessionID is created and then temp file is created in server's temporary
directory.
Diffent user has different SessionID and after session_destory called then all SessionIDs stored in Server and Cookies are recovered. You can rewrite this behavior by implementing SessionHandlerInterface. Of cause many web framework support this,Laravel has not exception.
Here is the document:
custom-session-drivers
I don't know how complicate it is to code it into laravel but this could be one solution:
You use a different session name, has to be a string, and code it into the url every time so the application knows which user made a request. So you can call the session variables by a normal name.
<?php
if(isset($_GET['id']) && !empty($_GET['id']))
session_name($_GET['id']);
session_start();
if(isset($_GET['user'])) {
$_SESSION['user'] = $_GET['user'];
}
if(!empty($_SESSION['user']))
echo "Hello ".$_SESSION['user'];

PHP session overlapping for two customers

Have a session problem with application when opened in multiple tabs of a browser.
In my project a user can have multiple log in id's so he could log into the app with two id's
at the same time as two diferent users. but when they try to log in with two id in multiple
tabs of a browser. the same session of the browser is being shared and the data gets messed up.
Any insights to solve this issue?
I see a pattern in mail.yahoo.com , if i log into my mail.yahoo with one user id and try to login in
to other user id in the new tab. one of them logs out. Any idea how this could be done...
Thanks
Piecing this together from against other answers it sounds like you need multiple application streams.
That is, you have a situation where you need multiple "users" to be logged in to the application on different tabs on the same browser, same machine.
This isn't because they are different people using the machine, but rather the same person working with different personas.
It turns out, I've implemented something similar in the past myself, in order for managers to be able to "ghost" through a system as their staff members. They log in as the other user, but in a read only mode so they can see what's going on.
OK. So how to do it.
Put simply - the session isn't enough - you need more than that. The session ID is stored in a cookie on the client machine and there isn't really much you can do about the set-up - one browser = one session.
However, what you can do is split that session up with an application stream, or application context.
That is, don't store anything in the root of your session - split your session into distinct components into which you have a set-up identical to your current session.
The key for each session is then the "application stream" key. You need to pass this around in your URLs.
E.g.
Your current session may have a simple set-up:
$_SESSION['user'] = 'some username';
$_SESSION['role'] = 'power user';
Instead you store that as:
$_SESSION[0]['user'] = 'some username';
$_SESSION[0]['role'] = 'power user';
On all urls you add:
&appId=0
And whenever you reference your session you use something like:
$username = $_SESSION[ $_GET['appId'] ]['user'];
Obviously, you wrap all this up in a nice session handling class, but that's the basic idea.
If you want a link that generates a new login page with a new application stream, you simply change the appId on the link (or completely omit it and trap that in your login code).
E.g.
$sLoginLink = "<a href='/login.php?appId=" . generateNewAppStreamId() . "' target='_BLANK'>New Login Screen</a>";
As everything is still stored in the session, the whole of your application should work exactly the same - just as long as you always have the appId on every URL in the system.
I've tried to make the explanation as simple as possible - forgive me if I've used too many words.
If you want to use session then you must arrange such mechanism that only one user can be logged in same browser. At login page, check availability of session and it is already have a value than redirect your page to any logged in page like home, profile or whatever you have.
When the user logs out or logs in using a different user ID you must use session_regenerate_id() to force PHP use a different cookie for the new login.
This is actually the best practice on logout.
If you want to have two users logged in simultaneously from the same browser you have to put something in the URL to tell them apart. For example, after login, user #1 will see all the pages as http://www.example.org/1/... and user #2 will have its own customized URL (http://www.example.org/2/...). Then you need to use session_set_cookie_params() for each user with the correct value for parameter $path ('/1' for user #1, '/2' for user #2 and so on).
It's not recommended to use the user ID as customized user directory but to generate a hash from it.

How to destroy a specific PHP session

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(); ?>

Letting users try your web app before sign-up: sessions or temp db?

I've seen a few instances now where web applications are letting try them out without you having to sign-up (though to save you need to of course).
example: try at http://minutedock.com/
I'm wondering about doing this for my own web app and the fundamental question is whether to store their info into sessions or into a temp user table?
The temp user table would allow logging and potentially be less of a hit on the server, correct?
Is there a best practice here?
It should work exactly the same way the application usually works, with the only difference being that a flag like thisIsATrialUser is set. You shouldn't create two different ways to do things internally.
Create a class of user, lets call it your Anonymous User Type. Give all unauthenticated users anonymous accounts (you have to clean up old accounts at some point). Use a persistent cookie to associate old users with their anonymous account. Make them authenticate themselves whenever they need to perform something that requires payment or full registration. Change their user type to something like Regular User Type once they are authenticated so you can keep all the information that was already attached to them when they where anonymous.
This allows tracking and storing of potential information like shopping carts without requiring registration upfront. Your code shouldn't have to change much if you treat anonymous user similarly to regular users. Otherwise you have to create an entirely new set of code to manage special users that are not stored in your master user table.
To clean up the data added by trial users, you can create a script to delete all the data that was created lifetime of cookie + 1 day and owned by any trial user. You can auto-pilot the script with nightly cron.

Categories