When a user successfully authenticates on my site, i store their user id in session: $_SESSION['user_id']
I then use this throughout the site to check if the user can perform certain actions. e.g.
if(isset($_SESSION['user_id'])){
//User is logged in, allow the following.
...
}
...
if ( $_SESSION['user_id'] == $comment_user ) {
//User owns the comment, go ahead and delete it.
...
}
However, if i discover that a signed in user has malicious purposes, how can i kill their login session so that they cannot perform these secure actions?
To block the user, on the db I can invalidate their login details, or add them to a blocked list that is checked upon authentication so that they can no longer authenticate. However, this would only have effect when they next attempt to log in. As long as the current session remains active and their user id is stored in session, they are considered authenticated..
Is there a way to unset a specific session, forcing a logout? How?
If not, what is the best way to make sure blocked users cannot continue to access secure areas on the site? e.g. My only idea is rather than just checking if(isset($_SESSION['user_id'])), an additional check can be added to make sure the user_id hasn't been added to a "blocked users" list on the db. I just don't like that another db request is made to check if the user has been to a blocked list each time they perform some action. Especially because blocking a user would be a rare occurrence. Is there a way to check if the user has been blocked without going to the db?
Thanks!
Edit
Most answers so far address how to unset/destroy a session, or how to block a user from their next login attempt. I guess the only question remaining then is how to check whether a user has been blocked while they are currently logged in. Is there is a way to do this without going to the DB to check a "blocked users" list each time a user performs an action. This relates to my main issue, which in bold italics above. If the user is blocked then i can immediately destroy the session (forcing a logout) and they will also be prevented from authenticating again.
If you know the user ID, you can always do something like:
$maliciousUsers = array(1,3,19,24);
if(in_array($_SESSION['user_id'], $maliciousUsers)){
#session_destroy();
}
I would do the $maliciousUsers array as a table in the database. This way, if you see something happening, toss their ID into the table, and it will be reflected. If they are able to authenticate and receive a $_SESSION['user_id'] then, this will destroy it.
when using sessions for authentication it is traditionally done with a username and some sort of hashed password stored as session variables. Here's a good resource on that: php sessions to authenticate user on login form
to end a user's session:
with your setup you can simply remove the session variable for the user to end their session
unset($_SESSION['user_id']);
or you can simply end the session like this:
session_destroy();
I have a tendency to put in a self destruct in the sessions table. on their next login, the app checks this.
if (!!$_SESSION['data']['self_destruct'])
{
session_destroy();
header('Location:/');
exit;
}
Presuming you're using a DB, storing the session identifier in there and banning them from any future logins, then the easiest way of achieving this is to additionally delete their session file from your file-system.
Finding session files
PHP sessions are often stored in the /temp or /tmp or /var/lib/php5/ directory (It varies) - although the default session.save_path is set to "", you can set the location by using:
session_save_path('/path/to/session/dir');
Or even in your .htaccess file:
php_value session.save_path /path/to/session/dir/
How session files are stored
Session files are prefixed with sess_ within a file system:
-rw------- 1 www-data www-data 0 2013-04-19 05:39 sess_141d2215ce74452ea6b1f69eea228159
Which, in the above example contains:
AutoLogout|s:4:"3600";FirstName|s:4:"John";Lang|s:2:"en";LastLogin|s:19:"2013-04-19 17:26:18";LastName|s:8:"Smith";RegDate|s:19:"2012-11-12 17:18:13";TimeOut|i:1366421178;UserEmail|s:22:"johnsmith#domain.com";UserId|s:1:"3";authenticatedUser|s:22:"johnsmith#domain.com";year|s:4:"2013";
As long as you have a record of their ID (assuming in your DB), you can delete them programatically.
Deleting session files instantly using PHP
PHP provides the ability to delete a file using unlink() and thus, when banning a user and preventing them from logging in (in the future), you can also ban them instantly by appending something like this to your banning function or creating an instant-kick function, using something like:
$sessionID = 'sess_'.$sessionIdFromDB;
$sessionDir = '/path/to/session/dir'; // Wherever your sessions are stored
unlink($sessionDir."/".$sessionID);
However, this technique assumes you have the permissions to delete the session file in question. If you don't, then you would need to adjust the file permissions or change them using chown() and/or chmod() or on your file-system.
Manual deletion
You can also delete session files manually using a terminal. Whilst this might seem pointless, I've seen it used in the past to instantaneously kick all users out prior to doing something business specific:
//SSH
cd /path/to/session/dir
rm -rf sess_*
Which, once executed, invalidates all user sessions.
Is there a way to unset a specific session, forcing a logout? How?
Better To Perform a Quick Logout
May be late but commented
//Change Accordingly!
function doLogout()
{
//clear session from globals
$_SESSION = array();
//clear session from disk
session_destroy();
//delete the session cookie using setcookie.
$cookieParams = session_get_cookie_params();
setcookie(session_name(), '', 0, $cookieParams['path'], $cookieParams['domain'], $cookieParams['secure'], $cookieParams['httponly']);
//unset the session variable
unset($_SESSION);
doBlock();
}
function doBlock()
{
//Start and Set Blocking session ,presence of it must be
//validated at first on any secure Areas Entrance ,
//it may not be secure if Session is Cleared by end Mal User) ,
// if extreme security is needed then
//Ugly block Remote IP is needed //(12-24 hr) Block
}
your Quest may have duplicates : Best way to completely destroy a session - even if the browser is not closed
How to remove a variable from a PHP session array
Related
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).
I am trying to understand security when it comes to session cookies in php. I've been reading a lot about it, but I still lack the specifics. I need the basics, someone to show examples.
For example: Do I place session_regenerate_id() before every session cookie? What more shall I think about. I am asking about specifics in code - examples if possible.
Thank you very much.
I am using 4 session cookies after logging in.
SESSION "site_logged_in" = true
SESSION "site_user_nr" = the number of the user to access user_table_nr
SESSION "site_user_id" = the user's id to use when changing data in tables
SESSION "site_user_name" = the name of the user to display on page
When I check if the user has access, I check if all 4 cookies are set, and if site_logged_in is set to true.
Are there better ways? Do I have the completely wrong idea about this? Can users easily be hacked?
In fact you need to have only one session in your website. When you call session_start() session is being created on server and user automatically gets session cookie. Think like session is a some sort of container that placed on the server, you can put whatever you want in that container. However session cookie is just a key to access that container on the server.
It means that you can safely put some data in the $_SESSION and only the user that have cookie with matching session id can read it.
About users being hacked. Yes they can be hacked as long as you don't use HTTPS connection, because cookies and all other data is being transferred in clear text, so if someone intercept users cookie he can access the data stored in the session.
Always use a security token for logging users. This security token could be generated by using crypt(). After logging users in, change the security token periodically until they log out. Also keep the server backup of all the session variables including the security token (in a database). This would also help you to track user login history.
One more personal suggestion: Never use any data from the database as session variables without encrypting it with any of the hashing functions or functions like crypt().
The session information is stored server-side. What you should check is that they're logged in, and that they exists/can log in (in case of deletions/bans).
As you're checking they exist/can log in, you can pull the other information from the database such as name, nr and so on. All you really need is a key called 'logged_in_user' or something that stores the ID of the logged in user. As Alex Amiryan said, the cookie can be copied, so you might also want to store the IP address of the last accessing view in the session, so you can try to ensure security.
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.