Two questions regarding session timeouts in cherrypy:
1) Is there a way to determine the remaining time in a session? This is related to trying to use http://plugins.jquery.com/epilgrim.sessionTimeoutHandler/
2) Is there a way to make a call to cherrypy NOT reset the timeout, such that the plugin above could call a URL to determine the time remaining in the session without resetting said time
Edit to help clarify: The purpose here is to be able to have a client-side process that periodically queries the server via AJAX to determine the amount of time left in a users session. This is to overcome difficulties with keeping a client side session timeout timer in-sync with the server-side timer - I'd like to simply have the client ask the server "how much time do I have left?" and act accordingly. Of course, if the act of asking resets the timeout, then this won't work, as the AJAX "time left" requests would essentially become a session keep-alive. So I need to be able to make an AJAX query to the server without resetting the session timeout timer for the user.
I believe cherrypy uses the expiration time in the cookie with the key session_id. Mine says:
Wed 22 Jan 2014 03:44:31 PM EST
You could extend the expiration with your set of circumstances and edit the session cookie.
EDIT: You will also need to extend the server timeout...
cherrypy.request.config.update({'tools.sessions.timeout': 60})
https://groups.google.com/forum/#!topic/cherrypy-users/2yrG79QoYFQ
Hope this helps!
You need to subclass the session and add a "stats" function to it and a flag to prevent saving in the session "stats" request handler. Or disable sessions in the config for the "stats" path and load session exp info directly from your storage without using normal session class.
I have found the answer to 2) question while going through source code of cherrypy session class. Apparently, you do not want to save session after serving such requests - this will then also not update expiration time (and will not save any changes to session object).
I found in the source code that setting cherrypy.serving.request._sessionsaved = True does exactly that. And added decorator for convinience:
def nosessionsave( func ):
"""
Decorator to avoid session saving and thus not resetting session timeout.
"""
def decorate( *args, **data ):
cherrypy.serving.request._sessionsaved = True
return func( *args, **data )
return decorate
Just add #nosessionsave before method def.
Related
Our Django application has the following session management requirements.
Sessions expire when the user closes the browser.
Sessions expire after a period of inactivity.
Detect when a session expires due to inactivity and display appropriate message to the user.
Warn users of a impending session expiry a few minutes before the end of the inactivity period. Along with the warning, provide users an option to extend their session.
If user is working on a long business activity within the app that doesn't involve requests being sent to the server, the session must not timeout.
After reading the documentation, Django code and some blog posts related to this, I have come up with the following implementation approach.
Requirement 1
This requirement is easily implemented by setting SESSION_EXPIRE_AT_BROWSER_CLOSE to True.
Requirement 2
I have seen a few recommendations to use SESSION_COOKIE_AGE to set the session expiry period. But this method has the following problems.
The session always expires at the end of the SESSION_COOKIE_AGE even if the user is actively using the application. (This can be prevented by setting the session expiry to SESSION_COOKIE_AGE on every request using a custom middleware or by saving the session on every request by setting SESSION_SAVE_EVERY_REQUEST to true. But the next problem is unavoidable due to the use of SESSION_COOKIE_AGE.)
Due to the way cookies work, SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE are mutually exclusive i.e. the cookie either expires on browser close or at the specified expiry time. If SESSION_COOKIE_AGE is used and the user closes the browser before the cookie expires, the cookie is retained and reopening the browser will allow the user (or anyone else) into the system without being re-authenticated.
Django relies only on the cookie being present to determine if the session is active. It doesn't check the session expiry date stored with the session.
The following method could be used to implemented this requirement and to workaround the problems mentioned above.
Do not set SESSION_COOKIE_AGE.
Set the expiry date of the session to be 'current time + inactivity period' on every request.
Override process_request in SessionMiddleware and check for session expiry. Discard the session if it has expired.
Requirement 3
When we detect that the session has expired (in the custom SessionMiddleware above), set an attribute on the request to indicate session expiry. This attribute can be used to display an appropriate message to the user.
Requirement 4
Use JavaScript to detect user inactivity, provide the warning and also an option to extend the session. If the user wishes to extend, send a keep alive pulse to the server to extend the session.
Requirement 5
Use JavaScript to detect user activity (during the long business operation) and send keep alive pulses to the server to prevent session from expiring.
The above implementation approach seem very elaborate and I was wondering if there might a simpler method (especially for Requirement 2).
Any insights will be highly appreciated.
I am just pretty new to use Django.
I wanted to make session expire if logged user close browser or are in idle(inactivity timeout) for some amount of time. When I googled it to figure out, this SOF question came up first. Thanks to nice answer, I looked up resources to understand how middlewares works during request/response cycle in Django. It was very helpful.
I was about to apply custom middleware into my code following top answer in here. But I was still little bit suspicious because best answer in here was edited in 2011. I took more time to search little bit from recent search result and came up with simple way.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True
I didn't check other browsers but chrome.
A session expired when I closed a browser even if SESSION_COOKIE_AGE set.
Only when I was idle for more than 10 seconds, A session expired. Thanks to SESSION_SAVE_EVERY_REQUEST, whenever you occur new request, It saves the session and updates timeout to expire
To change this default behavior, set the SESSION_SAVE_EVERY_REQUEST setting to True. When set to True, Django will save the session to the database on every single request.
Note that the session cookie is only sent when a session has been created or modified. If SESSION_SAVE_EVERY_REQUEST is True, the session cookie will be sent on every request.
Similarly, the expires part of a session cookie is updated each time the session cookie is sent.
django manual 1.10
I just leave answer so that some people who is a kind of new in Django like me don't spend much time to find out solution as a way I did.
Here's an idea... Expire the session on browser close with the SESSION_EXPIRE_AT_BROWSER_CLOSE setting. Then set a timestamp in the session on every request like so.
request.session['last_activity'] = datetime.now()
and add a middleware to detect if the session is expired. something like this should handle the whole process...
from datetime import datetime
from django.http import HttpResponseRedirect
class SessionExpiredMiddleware:
def process_request(request):
last_activity = request.session['last_activity']
now = datetime.now()
if (now - last_activity).minutes > 10:
# Do logout / expire session
# and then...
return HttpResponseRedirect("LOGIN_PAGE_URL")
if not request.is_ajax():
# don't set this for ajax requests or else your
# expired session checks will keep the session from
# expiring :)
request.session['last_activity'] = now
Then you just have to make some urls and views to return relevant data to the ajax calls regarding the session expiry.
when the user opts to "renew" the session, so to speak, all you have to do is set requeset.session['last_activity'] to the current time again
Obviously this code is only a start... but it should get you on the right path
django-session-security does just that...
... with an additional requirement: if the server doesn't respond or an attacker disconnected the internet connection: it should expire anyway.
Disclamer: I maintain this app. But I've been watching this thread for a very, very long time :)
One easy way to satisfy your second requirement would be to set SESSION_COOKIE_AGE value in settings.py to a suitable amount of seconds. For instance:
SESSION_COOKIE_AGE = 600 #10 minutes.
However, by only doing this the session will expire after 10 minutes whether or not the user exhibits some activity. To deal with this issue, expiration time can be automatically renewed (for another extra 10 minutes) every time the user performs any kind of request with the following sentence:
request.session.set_expiry(request.session.get_expiry_age())
also you can use
stackoverflow build in functions
SESSION_SAVE_EVERY_REQUEST = True
In the first request, you can set the session expiry as
self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds
And when using the access_key and token,
try:
key = self.request.session['access_key']
except KeyError:
age = self.request.session.get_expiry_age()
if age > set_age:
#redirect to login page
I'm using Django 3.2 and i recommend using the django-auto-logout package.
It allows active time and idle time session control.
In the template you can use variables together with Javascript.
I'm using Flask builtin session mecanism.
Here is my understanding of session mecanism (with flask) :
all session data are stored in a signed cookie (with app.secret_key)
when a session data is modified, the cookie is changed
session's data are protected against write client side (due to signature) but not against read
Imagine the following scenario :
In my session I put a variable try_number=3
Each time the user make an action, a decrease this number
If this number is equal to 0, action is forbidden
The user connect to the application for the first time, the application send a Set-Cookie: sesssion=Flask.sign("try_number=3"), let's call this cookie COOKIE_A.
The user perform his first action, he send COOKIE_A, the application reply with Set-Cookie: sesssion=Flask.sign("try_number=2"), let's call this cookie COOKIE_B.
Now, if the user perform another action, but doesn't use COOKIE_B but COOKIE_A again (using curl for exemple), the cookie is still signed, and will be handled by the server, with try_number=3.
Therefore, only using the COOKIE_A for all operation, he will be able to "spoof" session mecanism, and make unlimited action with the same session.
Is there any builtin mecanism to prevent this ?
(I'm not talking about snippet for using sqlite / redis, but builtin solution)
This is not a failure of the security of Flask's cookies, it's a failure of your counter design. There is no built in protection against replay attacks.
You can shorten the expiration time of the session cookie. This doesn't really solve the problem, it just makes the window smaller. It also makes the session inconvenient for regular use, which would annoy your normal users.
Ultimately, you'll have to store some information on the server and check against it. You could send a nonce with every request and keep a store of which ones have been sent back, ignoring ones that have been seen before. You could also just store all session information (except some identifying key) on the server side, so it can't be re-sent.
How do I create a new clean session and invalidate the current one in Flask?
Do I use make_null_session() or open_session()?
I do this by calling session.clear().
EDIT:
After reading your comment in another answer, I see that you're trying to prevent a replay attack that might be made using a cookie that was issued in the past. I solved that problem as much as possible* with this approach:
Override SecureCookieSessionInterface.save_session(), copying the code from the overridden version rather than calling it.
When the overridden version of save_session() calls save_cookie(), make it pass a session_expires argument 30 minutes in the future. This causes cookies more than 30 minutes old to be considered invalid.
Make the overridden version of save_session() update a session variable every so often, to make sure the cookie and its session_expires time get rewritten regularly. (I name this session variable '_refresh' and store the current time in it, then rewrite it only if more than a few seconds have passed since the last-stored time. This optimization avoids rewriting the cookie on every HTTP request.)
Duplicating Flask code in the custom save_session() makes this approach a bit ugly and brittle, but it is necessary in order to change the arguments passed to save_cookie(). It would be nice if Flask made this easier, or at least implemented its own safeguard against replay attacks.
*WARNING: This approach by itself will not stop replay attacks that might happen during a session cookie's valid lifetime. This fundamental problem with cookie-based sessions is discussed in RFC 6896 and A Secure Cookie Protocol by Liu, Kovacs, Huang, Gouda.
If you have security concerns (and everyone should have) There is the answer:
This is not REALLY possible
Flask uses cookie-based sessions. When you edit or delete session, you send a REQUEST to CLIENT to remove the cookie, normal clients (browsers) will do. But if session hijacked by an attacker, the attacker's session remains valid.
You can add an after_request callback to remove the session cookie if a particular flag is set:
#app.after_request
def remove_if_invalid(response):
if "__invalidate__" in session:
response.delete_cookie(app.session_cookie_name)
return response
Then you simply set that session key whenever you want to invalidate the session:
#app.route("/logout")
def logout():
session["__invalidate__"] = True
return redirect(url_for("index"))
See also: http://werkzeug.pocoo.org/docs/wrappers/#werkzeug.wrappers.BaseResponse.delete_cookie
If you use default flask sessions and set the app.permanent_session_lifetime, then the session will not work if a user tries to replay the same session as long as the session has expired.If you look at the source code for open_session, there is line:
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
Our Django application has the following session management requirements.
Sessions expire when the user closes the browser.
Sessions expire after a period of inactivity.
Detect when a session expires due to inactivity and display appropriate message to the user.
Warn users of a impending session expiry a few minutes before the end of the inactivity period. Along with the warning, provide users an option to extend their session.
If user is working on a long business activity within the app that doesn't involve requests being sent to the server, the session must not timeout.
After reading the documentation, Django code and some blog posts related to this, I have come up with the following implementation approach.
Requirement 1
This requirement is easily implemented by setting SESSION_EXPIRE_AT_BROWSER_CLOSE to True.
Requirement 2
I have seen a few recommendations to use SESSION_COOKIE_AGE to set the session expiry period. But this method has the following problems.
The session always expires at the end of the SESSION_COOKIE_AGE even if the user is actively using the application. (This can be prevented by setting the session expiry to SESSION_COOKIE_AGE on every request using a custom middleware or by saving the session on every request by setting SESSION_SAVE_EVERY_REQUEST to true. But the next problem is unavoidable due to the use of SESSION_COOKIE_AGE.)
Due to the way cookies work, SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE are mutually exclusive i.e. the cookie either expires on browser close or at the specified expiry time. If SESSION_COOKIE_AGE is used and the user closes the browser before the cookie expires, the cookie is retained and reopening the browser will allow the user (or anyone else) into the system without being re-authenticated.
Django relies only on the cookie being present to determine if the session is active. It doesn't check the session expiry date stored with the session.
The following method could be used to implemented this requirement and to workaround the problems mentioned above.
Do not set SESSION_COOKIE_AGE.
Set the expiry date of the session to be 'current time + inactivity period' on every request.
Override process_request in SessionMiddleware and check for session expiry. Discard the session if it has expired.
Requirement 3
When we detect that the session has expired (in the custom SessionMiddleware above), set an attribute on the request to indicate session expiry. This attribute can be used to display an appropriate message to the user.
Requirement 4
Use JavaScript to detect user inactivity, provide the warning and also an option to extend the session. If the user wishes to extend, send a keep alive pulse to the server to extend the session.
Requirement 5
Use JavaScript to detect user activity (during the long business operation) and send keep alive pulses to the server to prevent session from expiring.
The above implementation approach seem very elaborate and I was wondering if there might a simpler method (especially for Requirement 2).
Any insights will be highly appreciated.
I am just pretty new to use Django.
I wanted to make session expire if logged user close browser or are in idle(inactivity timeout) for some amount of time. When I googled it to figure out, this SOF question came up first. Thanks to nice answer, I looked up resources to understand how middlewares works during request/response cycle in Django. It was very helpful.
I was about to apply custom middleware into my code following top answer in here. But I was still little bit suspicious because best answer in here was edited in 2011. I took more time to search little bit from recent search result and came up with simple way.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True
I didn't check other browsers but chrome.
A session expired when I closed a browser even if SESSION_COOKIE_AGE set.
Only when I was idle for more than 10 seconds, A session expired. Thanks to SESSION_SAVE_EVERY_REQUEST, whenever you occur new request, It saves the session and updates timeout to expire
To change this default behavior, set the SESSION_SAVE_EVERY_REQUEST setting to True. When set to True, Django will save the session to the database on every single request.
Note that the session cookie is only sent when a session has been created or modified. If SESSION_SAVE_EVERY_REQUEST is True, the session cookie will be sent on every request.
Similarly, the expires part of a session cookie is updated each time the session cookie is sent.
django manual 1.10
I just leave answer so that some people who is a kind of new in Django like me don't spend much time to find out solution as a way I did.
Here's an idea... Expire the session on browser close with the SESSION_EXPIRE_AT_BROWSER_CLOSE setting. Then set a timestamp in the session on every request like so.
request.session['last_activity'] = datetime.now()
and add a middleware to detect if the session is expired. something like this should handle the whole process...
from datetime import datetime
from django.http import HttpResponseRedirect
class SessionExpiredMiddleware:
def process_request(request):
last_activity = request.session['last_activity']
now = datetime.now()
if (now - last_activity).minutes > 10:
# Do logout / expire session
# and then...
return HttpResponseRedirect("LOGIN_PAGE_URL")
if not request.is_ajax():
# don't set this for ajax requests or else your
# expired session checks will keep the session from
# expiring :)
request.session['last_activity'] = now
Then you just have to make some urls and views to return relevant data to the ajax calls regarding the session expiry.
when the user opts to "renew" the session, so to speak, all you have to do is set requeset.session['last_activity'] to the current time again
Obviously this code is only a start... but it should get you on the right path
django-session-security does just that...
... with an additional requirement: if the server doesn't respond or an attacker disconnected the internet connection: it should expire anyway.
Disclamer: I maintain this app. But I've been watching this thread for a very, very long time :)
One easy way to satisfy your second requirement would be to set SESSION_COOKIE_AGE value in settings.py to a suitable amount of seconds. For instance:
SESSION_COOKIE_AGE = 600 #10 minutes.
However, by only doing this the session will expire after 10 minutes whether or not the user exhibits some activity. To deal with this issue, expiration time can be automatically renewed (for another extra 10 minutes) every time the user performs any kind of request with the following sentence:
request.session.set_expiry(request.session.get_expiry_age())
also you can use
stackoverflow build in functions
SESSION_SAVE_EVERY_REQUEST = True
In the first request, you can set the session expiry as
self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds
And when using the access_key and token,
try:
key = self.request.session['access_key']
except KeyError:
age = self.request.session.get_expiry_age()
if age > set_age:
#redirect to login page
I'm using Django 3.2 and i recommend using the django-auto-logout package.
It allows active time and idle time session control.
In the template you can use variables together with Javascript.
I want keep track of a unique identifier for each browser that connects to my web application (that is written in Pylons.) I keep a cookie on the client to keep track of this, but if the cookie isn't present, then I want to generate a new unique identifier that will be sent back to the client with the response, but I also may want to access this value from other code used to generate the response.
Is attaching this value to pylons.request safe? Or do I need to do something like use threading_local to make a thread local that I reset when each new request is handled?
Why do you want a unique identifier? Basically every visitor already gets a unique identifier, his Session. Beaker, Pylons session and caching middleware, does all the work and tracks visitors, usually with a Session cookie. So don't care about tracking users, just use the Session for what it's made for, to store whatever user specific stuff you have .
from pylons import session
session["something"] = whatever()
session.save()
# somewhen later
something = session["something"]
Whatever you were to set on the request will only survive for the duration of the request. the problem you are describing is more appropriately handled with a Session as TCH4k has said. It's already enabled in the middleware, so go ahead.