Zend_Session and Expiration - zend-framework

I need to set a very short session (3 minutes) upon hitting a specific page on my site. If someone hits that page again during that 3 minute session, the session should update to expire 3 minutes from that time.
On my "bootstrap" (it isn't a typical Zend bootstrap, but it is included in every page), I do the following:
$aSessionSaveHandlerConfig = array
(
"name" => "Sessions",
"primary" => "Session_ID",
"modifiedColumn" => "UpdateTimestamp",
"dataColumn" => "Data",
"lifetimeColumn" => "Lifetime",
);
$oSaveHandler = new Zend_Session_SaveHandler_DbTable($aSessionSaveHandlerConfig);
$oSaveHandler->setLifetime(App::$ReservationTimeout)->setOverrideLifetime(true);
Zend_Session::setSaveHandler($oSaveHandler);
ini_set("session.cookie_lifetime",App::$ReservationTimeout);
$aSessionOptions = array
(
"gc_probability" => 100,
"gc_divisor" => 100,
"gc_maxlifetime" => App::$ReservationTimeout,
"cookie_lifetime" => App::$ReservationTimeout,
);
Zend_Session::setOptions($aSessionOptions);
Then within the page that should create/update the session, I have:
App::$ReservationSession = new Zend_Session_Namespace("ReservationSession");
$oSaveHandler = Zend_Session::getSaveHandler();
$oSaveHandler->setLifetime(App::$ReservationTimeout);
I see the records in the database, the lifetime column is correct, but if i repeatedly hit the page that creates/updates the session, I get a new Session ID after 3 minutes passes (and the other one gets removed after garbage collection.
It appears the problem is getting the cookie to update it's time. Any ideas?

To get the session cookie to update its expiration time, you can use Zend_Session::rememberMe() to change the default lifetime of the cookie. Calling rememberMe() will also cause Zend_Session::regenerateId() to be called which generates a new session ID, copies old session data to the new session, and sends a new session cookie to the browser.
Try the following code and see if it solves your problem:
App::$ReservationSession = new Zend_Session_Namespace("ReservationSession");
$oSaveHandler = Zend_Session::getSaveHandler();
$oSaveHandler->setLifetime(App::$ReservationTimeout);
// Call remember me which will send a new session cookie with 3 minute expiration
// from the current time. Old session data is copied to the new one and the old
// session is deleted
Zend_Session::rememberMe(App::$ReservationTimeout);
See the manual section on Session Identifiers for more information, or see also How to reset a Zend rememberMe function on each automatic login?
UPDATE:
Given your comment, I came up with this solution that you can use.
What this does is start your session as usual and then checks a value in the session to see if the user had an existing session.
If they do have an session, it uses setcookie() to send an updated session cookie using the existing parameters (including session id), except it sets the expiration to time() + $ReservationTimeout. If they did not have a session, then there is no need to update the cookie since the expiration is already correct and it will be updated on their next request (assuming they visit before it expires).
App::$ReservationSession = new Zend_Session_Namespace("ReservationSession");
$oSaveHandler = Zend_Session::getSaveHandler();
$oSaveHandler->setLifetime(App::$ReservationTimeout);
if (!isset(App::$ReservationSession->hasSession)) {
// user had no session before or it was expired
App::$ReservationSession->hasSession = true;
} else {
// user has a valid session, update the cookie to expire 3 mins from now
$params = session_get_cookie_params();
$expire = time() + App::$ReservationTimeout;
setcookie(session_name(),
Zend_Session::getId(),
$expire,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']);
}
I tested the solution using the files session handler and it worked as expected, I think it should be fine for your situation as well.

Related

How to delete a session in cgi-perl?

I have a perl-cgi script through which I am trying to log in.
When the UserName and password are valid, I create a session and redirect a cookie to another page.
However, after the session expires(I have set the expiration time), I do not see it get deleted from the /tmp/sessions folder in this case. I have used the command to delete the session as well.
Can someone help me to delete the session once it expires? Also, does the cookie expire once the session is deleted?
use CGI::Session;
use CGI::Session::Tutorial;
use CGI::Session::Driver::file;
use CGI::Cookie;
my $session = new CGI::Session("driver:File", undef, {Directory=>"/tmp/sessions"});
my $sid = $session->id();
#my $cookie = $query->cookie(CGISESSID => $session->id);
my $cookie = $query->cookie(-name=>"CGISESSID",
-value=>$session->id,
-domain=>'abc.com',
-expires=>"+5m",
-path=>"/");
print $query->redirect(-uri => 'http://abc.cgi', -cookie => $cookie);
$session->param("UserName", $loginUserName);
$query->hidden( 'UserName', $loginUserName );
$session->expire("UserName",'1m');
$session->expire('+5m');
$session->delete();
To avoid confusion with ->delete, I'm going to use the word "remove" instead of "delete" to refer to the removal of the session from storage.
Can someone help me to delete the session once it expires?
The removal doesn't happen when the session expires. That would require having a continually running process. Furthermore, at no point does CGI::Session scan storage for expired sessions; that would take too long since it would require loading each and every session. Instead, CGI::Session only removes expired sessions when you try to load them.
#!/usr/bin/perl
use strict;
use warnings qw( all );
use feature qw( say );
use CGI::Session qw( );
use CGI::Session::Driver::file qw( );
my $session_id; # This represents the browser's cookie.
# These represent requests made the by the browser.
for my $request_num (1..3) {
my $session = CGI::Session->new("driver:file", $session_id, { Directory => "/tmp/sessions" });
$session->expire("1s");
$session_id = $session->id; # This represents setting the browser's cookie.
say "$request_num: ", $session->id;
say "$request_num: ", $session->param("foo") // "[undef]";
$session->param("foo" => "bar");
# This represents time passing by before the third request.
if ($request_num == 2) {
say "Letting session expire...";
sleep(2);
}
}
Output:
$ ./a
1: c57ab28952c6ed422c15f1a223f4b45d
1: [undef]
2: c57ab28952c6ed422c15f1a223f4b45d
2: bar
Letting session expire...
3: df8ba3b66f23a9a2a652520fa6b4c30b
3: [undef]
$ ls -1 /tmp/sessions
cgisess_df8ba3b66f23a9a2a652520fa6b4c30b
If you want to prevent files from accumulating on your drive, create a cron job that deletes old files.
find /tmp/sessions -mindepth 1 -maxdepth 1 -mtime 7 -delete
Also, does the cookie expire once the session is deleted?
No, the cookie expires when you tell it to expire. The thing is, it doesn't matter if the browser's cookie expires or not. For the second argument of new, there's no difference between passing undef, passing the id of a deleted session and passing the id of an expired session; you'll get a new session in all three cases. If anything, it's actually better if it doesn't expire as soon as the session expires because this allows the session to be removed (as demonstrated above).
How to delete a session in cgi-perl?
$session->delete is indeed the way to go, but the actual removal only happens when you would save (flush) the session.
$session->delete();
$session->flush(); # Or let `$session` get destroyed.
As the documentation notes
delete()
Sets the objects status to be "deleted". Subsequent read/write requests on the same object will fail. To physically delete it from the data store you need to call flush(). CGI::Session attempts to do this automatically when the object is being destroyed (usually as the script exits), but see "A Warning about Auto-flushing". (emphases mine)
You go on to ask:
Also, does the cookie expire once the session is deleted?
Of course not. You already sent a cookie to the user's browser with an expiration time of five minutes in the future. The cookie will expire then.
If, in the mean time, you have forced the expiration of the session on the server, the user's browser will still send the previously received cookie. Your application will just not find a session corresponding to the session identifier stored in the cookie.
You really need to understand the HTTP request/response cycle before taking one more step.
Per the CGI::Session documentation, deleteing a session "Sets the objects status to be "deleted". Subsequent read/write requests on the same object will fail. To physically delete it from the data store you need to call flush()." (emphasis mine)
Also, per the CGI::Session::Tutorial, "Expiring a session is the same as deleting it via delete(), but deletion takes place automatically." It is not necessary (or useful) to delete a session after it has expired.

Unable to get idsrv cookie to timeout instead of be persistent

I have a problem where my idsrv cookie never seems to have a physical expiry time. So users on shared computers are logging in as each other because nobody appears to close their browser to kill this cookie.
Can someone please shed some light on what I should be doing?
You need to use persistent cookies to set the expiration, this will persist the cookie over browser sessions but also allow you to set the expiry. You don't mention which version of ASP.NET you're using but here's an example using aspnet core (the third parameter here must be true to persist the cookie):
var result =
await _signInManager.PasswordSignInAsync(model.Email, model.Password, true, true);
There are other ways to sign in but one way or another you'll have an overload that will allow you to set the persistent flag.
Then elsewhere you need to set the expiry when setting up cookie options you can specify the expiry time, e.g. if using Asp.Net Identity:
services.AddIdentity<ApplicationUser, IdentityRole>(
o => o.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromMinutes(30));
(Bear in mind that if you are on core and you upgrade to or use v2.0 you'll need to use services.ConfigureApplicationCookie instead, see here).
Of course this might not eliminate your users swapping machines within the expiration period but you can make the expiry small. What you can also do is use the SlidingExpiration flag alongside the expiry:
The SlidingExpiration is set to true to instruct the middleware to re-issue a new cookie with a new expiration time any time it processes a request which is more than halfway through the expiration window.
Meaning you can decrease the expiration time and so long as the user is still active they'll get new cookies. So the above code could be adjusted to:
services.AddIdentity<ApplicationUser, IdentityRole>(o =>
{
o.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromMinutes(10);
o.Cookies.ApplicationCookie.SlidingExpiration = true;
});

How to generate different session ID every time an user logins

I am using Play Framework 2.5 for my web application.
In my application, the server side app generates a session id and put email address int it when provided creadentioal is valid, so that the app can judge where requested user is already logined or not using the session id.
Redirect(routes.Application.index).withSession("email" -> "xxx")
The server side app also discords session when an user logout.
Redirect(routes.Application.index).withSession
I checked the session id. The session id is always same even after I close my browser.
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
reload
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
logout
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
close the browser
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
It is easy for an attcher to guess session id for each account. So I want to generate different session ID every time an account logins. How can I do that?
Thanks.
From Docs
By default, there is no technical timeout for the Session. It expires when the user closes the web browser.
I am guessing as you didn't close the browser, the session remained the same after you logged-in again.
So, during logout, you can discard the old session using withNewSession and during login, create a new session using withSession
With the help of redis, you can generate random session id when user logs in every time.
That means that you will discard the play session instead of managing the user session using redis by youself.
Every time users login, you can generate session id for the user and restore it in redis and set the session expire time. when the request of users comes in, you can check the random session id within request.
update
when a user login, your back-end server can generate a randomId for the user, and put the random id into session. when the user logout, delete the random id. The code is like the following
class Application extends Controller {
def login() { implicit request =>
val canLogin: Boolean = // check the authority,such as secret code
if (canLogin) {
val loginRandomId = Random.alphanumeric // just an example, generate randomID as you want
//put key-value into redis. Maybe (loginRandomId, email) is what you want, and you can also set expiredate for the key
redis.set(loginRandomId, email)
Redirect(routes.Application.index).withSession("email" -> loginRandomId)
}
}
def index() { implicit request =>
val sessionValue = request.session.get("email");// sessionValue is randomId
val isExist = redis.exit(sessionValue)
if (isExist) {
//handle the request
} else {
// did not login, return
}
}
def logout() { implicit request =>
// when logout you should delete the key in redis
val sessionValue = request.session.get("email");
redis.delete(sessionValue)
}
}
Good luck

Mojolicious session expires versus default_expiration

I have a program where I want the session data to expire at an absolute Epoch time after a request. I don't want the expiration to update for every request.
default_expiration works but not expires.
This does not work:
post '/access' => sub {
my $self = shift;
my $user = $self->param('username');
if ($self->authenticate($user, $self->param('password'))) {
### Set this otherwise timeout refreshes for every request...
$self->session(expires => time + 120);
(...)
}
};
Mojolicious cookie set to 1 hour (3600s) the default...
$self->sessions->default_expiration(120) works but reset for every browser request.
I am using the Mojolicious::Plugin::Authentication plugin.
You can use the expiration key to set the same value as the default_expiration does. Before you set the value though, be sure to check to see if the key exists already and don't overwrite it if it does.

Ending or dropping an Asp.net Session

I'm creating a session to transfering data between asp.net pages. Here is my session create in first page:
Session["Data"]=depo.Value;
Response.Redirect("rapor.aspx");
I using it with rapor.aspx(second page):
TextBox1.Text = Session["Data"].ToString();
this process runs perfect.But after I read data from session,I will end(drop) the session,because I don't will occupying the server.I'dont will using timout,I'll ending(droping) the session after user getted the data on second page.is tehere any way to do ending(droping) asp.net session?i.e
Session["Data"].end ?
If you want to only remove the key "Data" from your session you can do:
Session.Remove("Data");
But if you want to completely end the session and delete it's contents, you can do:
Session.Abandon();
Session.Clear();
See How to Kill A Session or Session ID (ASP.NET/C#) for more discussion on this topic.
To destroy a session, use
Session.Abandon();
If you want to remove a specific item from the session use
Session.Remove("YourItem");
And if you only want to clear a value use
Session["YourItem"] = null;