Codeigniter - Session expiration and "remember me" feature - php

I'm building a "Remember Me" feature in Codeigniter, normally I see libraries/projects setting a cookie on the user with a token, this token gets saved in the database and is compared each time the user accesses the website.
In Codeigniter we can set the session expiration time though, this lead me to try a different approach, this is what I did:
I set the session_expiration in config to 0 (infinite session)
If the user leaves "Remember me" unchecked, I set a 2 hour time in the session and session destroy on window close.
So my login code looks like this:
if (!$this->input->post('remember_me')) {
$this->session->sess_expiration = 7200;
$this->session->sess_expire_on_close = TRUE;
}
$this->session->set_userdata($session_data);
And my config file:
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
I don't see people using this solution on projects, I have tested this out and it seems to work fine though.
SO, for my question, would you say this a safe practice to do? Any security dangers I should know about? Any input on this solution vs cookie+database token would be great.

The simpliest solution that I have found for this problem is to just modify the cookie created by Codeigniter by this way:
$this->session->set_userdata('user', $user); // a cookie has been created
if($this->input->post('remember_me'))
{
$this->load->helper('cookie');
$cookie = $this->input->cookie('ci_session'); // we get the cookie
$this->input->set_cookie('ci_session', $cookie, '35580000'); // and add one year to it's expiration
}

Also this can be done by editing/extending system Session library.
First: Set regular session expire time in config file.
Second: In user login function add remember me check-
if($remember)
{
$data['new_expiration'] = 60*60*24*30;//30 days
$this->session->sess_expiration = $data['new_expiration'];
}
$this->session->set_userdata($data);
Third: Edit system Session library [I am not sure whether extending Session will work or not]
Go to this line in sess_read() method
if (($session['last_activity'] + $this->sess_expiration) < $this->now)
Before that line add following code
if(isset($session['new_expiration'])){
$this->sess_expiration = $session['new_expiration'];
}
This works fine for me.

I can't say it's not right, but I can tell you my way of doing this:
First I set the session to expires on browser close with a default uptime of 7200.
Then:
The login sets session userdata
The "remember me" sets a separated cookie (I store an encrypted hash containing user's email+password+id ie: md5(pass+email+id))
Every time the user loads a page I control if the remember me cookie exist, if exist I create the user session.
The only thing I know is that session, uses an encryption key, a malicious attacker will take time to decrypt, so the less a session key exist the less time attacker has for decrypt the current key.
I always avoid session to not expire, so the Remember me, is always something not good for security I think, but anyway is the user to choose or not if to use that feature ;)

Related

Set session timeout based on the user role in Codeigniter

There is a configuration setting in Codeigniter for setting session expiration:
$config['sess_expiration'] = 14400; //in seconds
But this applies for all types of user roles (admin/frontend users). I would like to set a lifetime session for an admin and just want to apply above setting for frontend users.
How could I achieve that?
Session data get stored at server and it get destroy if browser will get closed. For lifetime login you need to make use of cookie
Ex. "Remember me option"
If you want to implement with session you need to do it manually: Ex.
if ($ROLE != 'admin' && isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
I have given example of core php you can implement it in codeigniter with
$this->session->userdata('LAST_ACTIVITY');
$this->load->helper('cookie');
$cookie = $this->input->cookie('ci_session');
$this->input->set_cookie('ci_session', $cookie, '31557600');
Although I'm not sure its a good idea to make a session never expire, you could probably set the session cookie to expire one year in the future if the user is logged in as a admin.

Is php session unchangeable from user end? [duplicate]

This question already has answers here:
Can a user modify a PHP session?
(3 answers)
Closed 7 years ago.
I am developing my own application which requires user login. All users and passwords (encrypted) are stored in a database. When a user tries to login, then it search in the database the username and password. If all is ok, then I store username in $_SESSION["username"], user role (admin, author etc) in $_SESSION["role"] and user website in $_SESSION["website"] (I need website to be stored because the application is like "multisite" - my applicaton is hosted on client hosting but the administration is on my server).
I read this Can a user alter the value of $_SESSION in PHP? and I don't understand. Is this method secure (of storing data and if user is logged in) in a $_SESSION?
Can the user change the session content? (for example, if user is logged in and $_SESSION["website"] is "example.com", can the user change the session $_SESSION["website"] to "example.org" to ruin another website? If yes, how to avoid or what's the secure alternative of session?).
And please tell me what is session hijacking and how can this affect my site and also, how to make session_id dinamically to change?
Thank you so much!
$_SESSION is saved in the server, so the user cannot modify it ( Except the case of session hijacking)
Session() is server side as #kd0807 noted. For more info on Session Hijacking && Fixation:
http://phpsec.org/projects/guide/4.html
http://php.net/manual/en/session.security.php
Side note...
With the amount of variables I recommend an array for session['user'].
example....
$_SESSION['user'] => Array(
'userid'=> '123',
'username'=> 'some_joe',
'role' => 'customer', // user, customer, admin, moderator etc.
'website' => 'http://www.example.com'
);
// reading variables from array
$userid = $_SESSION['user']['userid'];
$username = $_SESSION['user']['username'];
// etc. etc.
Here are 3 very simplified functions I use.
// determine if session has started
Function HasSessionStarted() {
$result = false; // default to false
// Check if session has started
IF ((session_status() == PHP_SESSION_NONE) || (session_id() == '')) {
$result = true;
}
return $result;
}
// Set a session value
Function Set_Session($name, $value) {
/* #params value: can be a string or an array */
$new_session = HasSessionStarted(); // Check Session Status
IF ((isset($name)) && (isset($value))) {
IF ($new_session) { session_start(); }
$_SESSION[$name] = $value;
IF ($new_session) { session_write_close(); }
}
}
Function Unset_Session($name) {
$new_session = HasSessionStarted(); // Check Session Status
IF (isset($_SESSION[$name])) {
IF ($new_session) { session_start(); }
unset($_SESSION[$name]);
IF ($new_session) { session_write_close(); }
}
}
There is a cookie stored in the browser usually PHPSESSID which identifies which server session the user is using. If a user were able to steal it (this usually happens through XSS vulnerabilities) the user could potentially take control of another users session.
The session data itself is stored on the server and could only be modified if a user were somehow able to upload and execute a malicious script in the server
No, Until and unless the php code itself reveals the PHP session, which can be used to session stealing, and the session could not be changed from the user end until and unless the there is some functionality given by you yourself to change the session from the front end.
`$_SESSION` variables are stored in the server and hence cannot be modified by the user.
One of the best practices is that we must keep changing the session id from our end.
Thats why we use a function called session_regenerate_id().
This function that will replace the current session ID with a new one, and keep the current session information, so the use will not be logged out.
To answer your question in comment:
Whenever you start a session, server will send back a cookie which will contain the session id, the cookie name will be PHPSESSID which is the default name. You can also choose to change it. So this id is what that keeps changing when you use the session_regenerate_id function.
REASON WHY TO USE IT:
This mainly helps in preventing session fixation attacks.In this attack a malicious user will try to fix the session ID (SID) of another user. If he gets successful,the user will get all the access of the original user and will be able to do anything that the legitimate user can do.
So if you regenerate the session id the previous old session id will be no longer valid
You can get more info about session fixation IN OWASP WEBSITE
Can the user change the session content? (for example, if user is logged in and $_SESSION["username"] is "example.com", can the user change the session $_SESSION["username"] to "example.org" to ruin another website?
No. Sessions are stored on your server thus it would be impossible to directly change the session. On the other side, it all depends on the developer and how the interprets the client requests. For example, making
$_SESSION['last_website'] = isset($_SERVER['HTTP_REFERER'])
? $_SERVER['HTTP_REFERER']
: $_SERVER['REQUEST_URI'];
would eventually override the $_SESSION['last_website'].
Yes user cannot change session Variables...
if it hacked it can changed...
you need to get user id to change the $_SESSION["website"] in your current domain and use strict validation...
Otherwise they can hack it....

What is the best way to make "remember me" under php when using native sessions?

Previously i was creating additional cookie "rememberme" with unique hash, that was stored in the database, mapped to the user id.
If user had such cookie - website tried to find it's value in database, and if it was found session was setting up.
Later, developing new project i thought that it is maybe not very secure to generate this unique hash by myself, and keeping two cookies (native "PHPSESSID" + my "rememberme") for one operation (user identification) is overkill.
Maybe there is a way to setup not global session lifetime, but to setup it individually for different user sessions... or maybe it is better to keep user sessions in the database, mapped to the userid?
UPDATE 1
I thought if it is so hard to make "remember me" button, we can go another way - to make "Not my computer button". Idea is to set default cookie_lifetime for a week in php.ini (for example), and if user checkes this checkbox - we will set cookie_lifetime into zero using session_set_cookie_params function.
So, 1st question is - will session_set_cookie_params affect other users cookies (in documentation it is said, that session_set_cookie_params options will have effect until php process will be executing)
2d question is that if session_set_cookie_params is not affecting global settings, will session regeneration affect users, that don't want to keep a long-life cookie?
UPDATE 2: [Question 1 answer]
Just tested session_set_cookie_params function.
I wrote a script, that sets session cookie lifetime into zero using session_set_cookie_params and then executing for 30 seconds:
if ($_GET['test']) {
session_set_cookie_params (0);
while (true) {
sleep(1);
}
}
session_start();
So, in first browser i just started this script with ?test=1 parameter, just after that (while this script was executing) i started this script without parameters in the second browser. The answer is no - second browser's cookie was not affected. It had lifetime, that was specified in php.ini
UPDATE 3: [Question 2 answer]
Then, i've tried to check if regeneration affects session cookie lifetime, that was set by session_set_cookie_params.
Yes, it affects. If i set session cookie with customized lifetime, that was set by session_set_cookie_params, and then call session_regenerate_id(), cookie will have lifetime, set in php.ini
But, if we set session_set_cookie_params (0) before calling session_regenerate_id(), our cookie will have correct lifetime.
So, that's it! That was easy! 8)
Thank you, ladies and gentlemen!
If you want to do this only using sessions you can do the following if the user wants to be remembered:
if((isset($_POST['remember_me']) && $_POST['remember_me']) || ($_COOKIE['remember_me']) && $_COOKIE['remember_me'])) {
// store these cookies in an other directory to make sure they don't
// get deleted by the garbage collector when starting a "non-remeber-me"-session
$remember_me_dir = ini_get('session.save_path') . DS . "remember_me_sessions";
// create the directory if it doesn't exist
if (!is_dir($remember_me_dir)) {
mkdir($remember_me_dir);
}
// set the php.ini-directive (temporarily)
ini_set('session.save_path', $remember_me_dir);
// define lifetime of the cookie on client side
$expire_cookie = 60 * 60 * 24 * 30; // in seconds
session_set_cookie_params($expire_cookie);
// lifetime of the cookie on server side
// session file gets deleted after this timespan
// add a few seconds to make sure the browser deletes
// the cookie first.
$garbage_in = $expire_cookie + 600; // in seconds
// set the php-ini directive for the garbage collector of the session files.
ini_set('session.gc_maxlifetime', $garbage_in);
// send an additional cookie to keep track of the users
// which checked the 'remember_me' checkbox
setcookie('remember_me', 1, time() + $expire_cookie);
}
// now we are ready to start the session
// For all the users which didn't choose to check the 'remember_me' box
// the default settings in php.ini are used.
session_start();
Here you can read more about the session related php.ini-directives
As it was so hard to make "remember me" checkbox functionality, i came to another way, using only one cookie.
PREPARATION
1) I've prepared a form with three inputs:
"login" input [type=text]: user's login
"password" input [type=password]: user's password
"not my computer" input [type=checkbox]: that will tell us to use session cookie with lifetime = 0 (cookie must be deleted when browser will be closed)
2) I've set session.cookie_lifetime = 100500 to keep long-life cookies by default.
COOKIE SETUP
So, after user submits the form, we check - if he has selected to use short sessions - we call session_set_cookie_params(0) before setting session cookie to him (before actually using session_start()).
COOKIE REGENERATION
Then, when we need to regenerate session cookie, we can also do this easily with session_regenerate_id() function.
But we need to remember, that this function will re-set session cookie lifetime from php.ini by default.
So, we need also to call session_set_cookie_params() before regenerating a cookie.
BTW, You can store custom session cookie lifetime in $_SESSION.
It will look like this:
// Form handling, session setup
if ($_POST['not-my-computer']) {
session_set_cookie_params(0);
session_start();
$_SESSION['expires'] = 0;
}
// Session regeneration
if (isset($_SESSION['expires'])) {
session_set_cookie_params(0);
session_regenerate_id();
}
Details for this answer (and more deep explanations) you can find in the question text (while i was testing, i added answers/tests results there)

php session unset

Is it possible to unset a specific user session (one who is banned from the site)?
Each session contains the user's username.
Or is the only way to writing sessions in the database and checks whether the user is deleted from that record?
Thanks for any suggestion.
PHP doesn't keep track of what session IDs have been issued - when a session cookie comes in on a request and session_start() is called, it'll look in the session save directory for a file named with that session's ID (sess_XXXX) and load it up.
Unless your login system records the user's current session ID, you'll have to scan that save directory for the file that contains the user's session, and delete the file. Fortunately, it could be done with something as simple as:
$session_dir = session_save_path();
$out = exec("rm -f `grep -l $username $session_dir/*`");
You'd probably want something a bit more secure/safe, but that's the basics of it.
Just remove the user from your database.
I assume that you are checking login credentials.
You can add a timeout to your sessions like so:
define('SESSION_EXPIRE', 3600 * 5); //5 hours
if (!isset($_SESSION['CREATED'])) {
$_SESSION['CREATED'] = time();
} else if (time() - $_SESSION['CREATED'] > SESSION_EXPIRE) {
session_regenerate_id(true); // change session ID for the current session an invalidate old session ID
session_destroy();
session_start();
$_SESSION['CREATED'] = time(); // update creation time
}
I think the best method would be before allowing the user to comment, have PHP read your database and check if the individual has publish permissions. If not return an error.
Another thing you could do, which Facebook does, is have an AJAX call checking a PHP file every few minutes. The PHP file simply returns whether the user is logged on or off and if they are logged off, Javascript redirects them off the page.

PHP session lifetime problem

I'm using PHP5 here. I have made a login system that check's the username and password against the records in the database. I want to use sessions to store the logged value. For example, when I reach the zone where I "log in" the user succesfully:
if($errors = 0) {
$_SESSION['logged'] = "1";
}
The problem is that I want the $_SESSION['logged'] to stay active for let's say 5 minutes so when I do a if($_SESSION['logged'] == "1") after this time to return false. Also, I would like to delete this session after the user closes the browser. Basically, I want a session configuration so that the user can safely leave his desk and when him or somebody presses refresh after 10 minutes or enters again after the browser has been closed, the session to be already removed, and the access to be restricted.
Can anybody help? Thanks.
Use session_set_cookie_params() to change the lifetime of the session cookie. Note that by default, it is set to 0 which means that the cookie is set until the user exits the browser. You can do this in the following way:
/* Set to 0 if you want the session
cookie to be set until the user closes
the browser. Use time() + seconds
otherwise. */
session_set_cookie_params(0);
session_start();
Then check for the last activity time, updated each time someone visits a page.
if(($_SESSION['lastActivity'] + 300) < time()) {
// timeout, destroy the session.
session_destroy();
unset($_SESSION);
die('Timeout!');
} else {
$_SESSION['lastActivity'] = time();
}
Instead of setting it to one, why don't you set $_SESSION['logged_time'] = time(); and then check the time against time() in your application?
If you'd like to actually expire the entire session, the exact specifics can change depending on your session handler, but for the default session handler (and any other well behaved session handler) you'll want to check out http://us3.php.net/manual/en/session.configuration.php
You can change the configuration setting session.cookie_lifetime, e.g. in php.ini or a .htaccess file:
session.cookie_lifetime specifies the
lifetime of the cookie in seconds
which is sent to the browser. The
value 0 means "until the browser is
closed." Defaults to 0.
This means (I think) that you can't have both expiry based on a timeout and expiry when the browser is closed. So maybe the best bet is to keep the default and set your own timer in $_SESSION as others have suggested, thus rendering this answer pointless.
Sessions stay alive aslong as the user stays on your site. You will have to use cookies to set a specific timeout.

Categories