I want to add a "close other active sessions" button to my PHP web app.
I'm thinking of tracking (userid,sessionid,expiration) on a MySQL table and kill the sessions the following way:
$currentsessionid=session_id();
foreach($othersessions as $session){
sessionid($session['sessionid']);
session_start();
session_destroy();
}
mysql_query("DELETE FROM sessions WHERE userid = $currentuserid AND sessionid <> $currentsessionid");
session_id($currentsessionid);
session_start();
The table would also be updated after each session_start() if the user is logged, removing expired entries.
Expired entries are removed every time a user logs in.
Is this the proper approach? Any suggestions?
In PHP the sessions are normally isolated. You need to create your own session handler and write session (plus some extra tracking information) into the database so this become more easy to manage.
For example, like you have in your question, the userid. You then can search for sessions of a specific user.
Another field you should have is a timestamp so that you can let sessions expire, e.g. if older than X hours, you throw them away.
You can - if you like - also take a look if a user has got an existing session and import the old session. However this can have security implications. You need to think about what happens when an attacker logs on instead of the real user.
Can an attacker even throw the valid user out of the system then? That should be prevented.
Also take into consideration that you can take over the session data of a previous session under a new session ID. That is similar to session_regenerate_id(), a login should always regenerate the session id, as well as the logout and other, important steps (e.g. re-authentication before changing the email-address).
Related
So my goal here is to manage the users through session id, so to do that
Check clients cookie if there is a old session id, if not ask server for a new one and save in clients cookie, else take the id and request the server to resume a session with that id.
Code:
session_id($_POST["SESSID"]);
session_start();
2.use the session id in every request to fetch users data.
but i have two concerns:
isnt it unsecure to allow the client to provide a session id for the server? wont that open the application for abuse, where people will try guess others users session id?
wont the server lose the control of which session are expired? as long the client have the old session id , they can use it forever ?
EDIT: a possible solution:
So to adress my concerns, i modifed the code, to set a an expiration date to every session id, and if the old session ID is expired then the server sets a new one for the client, like the following:
session_id($_POST['SESSID']);
session_start();
if( isset($_SESSION['expires']) && $_SESSION['expires'] > time()){
//use old session
}else{
session_unset();
session_destroy();
session_start();
session_regenerate_id(true);
$_SESSION['expires'] = date(strtotime("+1 hour"));
// use new session
}
This vulnerability even has a name. :) It's called session fixation.
Edit:
To avoid session fixation and related session vulnerabilities, you should
not assign sessions to anonymous users (sessions take resources)
whenever privilege levels change, and most importantly, when a user logs in, assign a new session id (if there was already one, reassign a new one)
always generate session ids on the server, never take a session id from a client
use the built in session management features (as opposed to things like generating your own session id)
use a reasonable session timeout, both sliding and absolute, depending on your business case
Note that this is not a comprehensive list, and it is in no particular order.
I'm wondering what is happenning when a user logs in a website with or without checking a "stay logged in" checkbox.
From what I understand start_session creates a variable on the server and stores the session id on the client's browser in a cookie, destroyed when closing the said browser.
Following that reasoning, I guess that checking the "stay logged in" checkbox pushes back the expiration date by N seconds, which would be achieved by setting:
setcookie(session_name(), session_id(), time()+N);
In that case, I see no need to use cookies, at least for the logging process.
Am I right or awfully wrong? :)
There are a couple of typical ways a "stay logged in" box might be handled...
You could set the user's info in a persistent cookie, and look for that cookie.
You could create some unique ID (it better be a big one...like a GUID or a hash), store it in a persistent cookie, and let that serve as auth info.
Note that most solutions don't involve the user actually staying logged in; they just make it so that the user doesn't see another password prompt. Keeping the session alive and storing the session ID in a persistent cookie is technically possible, but for a site with a lot of users, that'd be quite a bit of extra space and load on the server.
The way I have written an option like that is to create a token and store it in the database along with the user ID. I then give that token to the browser as a cookie. Anytime a page request is done, I check to see first if the user has an active session, then if they have this token cookie. If they have a token cookie, I look into the database to see if it is valid and if so create a session with that user ID.
I'm sure this is an insecure, easily breached method, however.
Initially I came up with the following to see if a user is already logged in:
<?php
session_start();
if(!isset($_SESSION['sessionid'])) {
header("Location: login_form.php");
} else {
echo "You are logged in";
}
?>
$_SESSION['sessionid'] is set when the user manually logs in.
If the user checks "remember me" I set the session cookie's lifetime to be 10 years:
$lifetime = 24*60*60*365*10; // 10 years
setcookie(session_name(),session_id(),time()+ $lifetime,'/');
So now I need to figure out what to do on the server side.... Initially I was thinking of setting session.gc_maxlifetime to a high value so that the server's session data would live for a long time, but 10 years would be ridiculous. Now I'm thinking I should store the session ID in the user table and query that against the session ID. If there's a match, I'll auto log the user in.
My question is:
How do I get the session ID from the client?
My understanding is that it will be available after I call session_start(), but only if the server's session data is still available. If the session has expired (which happens depending on the value of session.gc_maxlifetime) a new session ID will get generated when session_start() is called. This would be problematic as it wouldn't match the last session ID that I stored in the user table.
So the ideas I have to read the session ID, after calling session_start() are:
1) $_SESSION['sessionid']
2) $id = session_id();
3) $_COOKIE["PHPSESSID"];
1 and 2 won't work if the server has destroyed the session data, so I don't think I can use these.
3 might work, but when I tried it (echo $_COOKIE["PHPSESSID"];) I was surprised because the session ID was appeared twice:
the output was this:
htknitopug4b6bv4ql9050pfg6 //htknitopug4b6bv4ql9050pfg6
I simply expected the output to be htknitopug4b6bv4ql9050pfg6.
Can anyone explain the duplicate entry of the session ID? If this behavior is consistent I could always read the first string into my database table.
The short answer is that you shouldn't do that. For reasons why, please see this answer.
As far as what to do instead, I would set a signed cookie (that post shows how) with a large random string unique for each user. Then, when loading the session if it is new, check for the cookie. Then look up the user based on that random string. If you find one, silently log the user back in.
This is a pretty standard remember-me function, but it avoids the pitfals of having long-running sessions, or using the session identifier for other things.
One thing to note, you really should be rotating your session identifier pretty often as well. I typically do it for every login/logout event as well as whenever the user does something sensitive (admin forms, posting content, etc). There's nothing wrong with rotating too much...
Hey, I'm trying to get my php website to basically "log out" (session_destroy()) when the same user logs in somewhere else. Is there a way to do this? To remotely destroy a specific session?
Thank guys!
Scott
It's certainly possible, using session_id. When the user logs in somewhere else, you can do this step before starting a new session for the new login:
// The hard part: find out what $old_session_id is
session_id($old_session_id);
session_start();
session_destroy();
// Now proceed to create a new session for the new login
This will destroy the old session on the server side, so when the other computer accesses your application again it will try to access a non-existent session and a new one will be created for it (in which the user is not logged in anymore).
The hard part is finding out what is the ID of the "old" session. There's no one-size-fits-all way of doing that; you need to have some mechanism in place to be able to tell that the session with id XXX belongs to the same user who is logging in now. If you are using database sessions this should be easy enough.
It's not necessary to create your own session handlers.
Simply store the session ID with the username in the database upon login.
Every time the user fetches a page, compare that user's session ID with the stored session ID.
If the session IDs don't match, it means the user has logged in somewhere else, and you should self-destruct.
I can imagine you could do this by using your own session handling. If you store you sessions in database, you could delete them from other app, if you needed to. You would identify the user by user name or something like that.
The best way is to create your own session handlers, if you have full control over how the sessions are stored/retrieved and controlled it's not that difficult to force a log out and it offers you a whole broad range of useful features. If you've got time.
But, for a quicker solution: Store the session ID from PHP in the database with the user, and check this in your isLoggedIn function - or whatever you use. If it doesn't match, force the logout.
Another thing you could do besides Jon's answer (which is great, +1), is initially check where the user came from (referer) and destroy the session if the user comes from another webpage than your own.
$referer = $_SERVER['HTTP_REFERER'];
$referer = parse_url($referer);
if($referer['host'] != "yoursite.com" || $referer['host'] != "www.yoursite.com") {
session_destroy();
}
source
I would like to suggest that what we can do is, get the time and add some addtional value (like manu1234567) and store in database when user log's in .
add that in session also.
now on each page compare both , and if that is equal then proceed , else forward to another page or give some msg .
now other part
when ever another user will login with same username and password, database will update
and for first person there will be error msg "some one logged in from some where else."
Note : time will always different . so there will be very very less chances that two values will be same.
I have set up a login system that checks a mysql db validating username,hashed password, and a banned column (0 means not banned and is the default value, 1 means banned). if there banned they obviously cannot loggin.
The problem is i'm new to php and having a hell of a time trying to figure out how to log out a user who is currently logged in. As it stands now my cookie will last for 2weeks, and even if i ban a user, their session will stay active thus they will have acess for 2weeks or less.
How can i force a user to reauthenticate, without penalizing the masses.
Your server knows what cookie is associated with each user. Why not just delete that cookie from its "current sessions" table?
If the cookie is just "username, who is logged in", you have a real problem, because instead of a magic number, the cookie contains real information, and it becomes trivial to forge. Then a malicious user could simply create a cookie saying "I am [admin], and I am logged in", and that's obviously a much larger problem. So if you can't just delete the session cookie from the "known cookies" table to solve this problem, you have a bigger problem to worry about.
If you are doing your authentication system completely on your own (kudos on that, BTW) you merely need to unset the session value that contains their authenticated status. So, if you used:
<?php
session_start();
if(isset($_SESSION['isloggedin']) && isBannedUser())
{
session_unset();
session_destroy();
}
?>
The pseudo-code above calls to a fictitious function called isBannedUser() to determine if they are banned or not. If they are, in my example above I call session_unset() to unset all values stored within the $_SESSION and then session_destroy() to completely close the session. Some would probably argue that you may not need to unset if you're destroying, but I have just gotten into the habit of cleaning up all variables and values that I make in code.
This should be in every page so that you check if they're banned as frequently as possible. With the $_SESSION destroyed the user is, effectively, kicked out of any part of your website that requires authentication. You will need to implement supporting code in your login workflow that keeps a banned user from logging back in.
Hope this is helpful.
If you are storing the session data in a database, delete the row with their session information. Or, delete the file if using files. Then next page load, the login system shouldnt be able to verify their login information (since there's no info for that session), and prompt them to re-login.
On a file-based sessions system, maintain a counter somewhere which triggers a periodic check of the database for updates, something like:
<?php
session_start();
$_SESSION['hits_since_last_verification']++;
if ($_SESSION['hits_since_last_verification'] > 100) {
$banished = ... // get banishment flag from database
if ($banished) {
$_SESSION['loggedIn'] = FALSE;
}
}
?>
and then decide how long you'd like a banned user to be allowed to continue poking around the site until the session data is refreshed and they get booted.
Another option is an external script which runs through the session storage directory, loads each in turn, checks if the user's banned, and updates the session file as appropriate. But this would be painful on even a moderately busy system as you open/unserialize/check banishment/update/reserialize potentially thousands of session files every X minutes.
maybe you want to store the sessions in another table and delete it when you ban the user.
you know. check the table every time the user load a session and if the user isnt there. delete the cookie and destroy the session (sending him to the index of your site)
You can store the userID in the session and on each request, you check if he's banned (SQL query). If true, you destroy his session so he's forced to reauthenticate. Which fails of course because he's banned.