Django key based session expiration - django

I have a website which contains several rule sets for different kind of users.
One of the rules (permission) depends on the session expiration.
For instance, an unauthenticated users' session must be flushed when browser is closed however, authenticated users' sessions should live for a constant time.
Furthermore, for authenticated users some keys in the session may be deleted when the browser is closed but other should be kept alive.
How can I achieve this key-based session expiration in Django ?

You can do this by using the set_expiry method on request.session. The method takes either an integer for number of seconds to expire the session, a datetime or timedelta for when the session should expire, the integer 0 to indicate the session should expire at browser close time or None to indicate that the session should fall-back to the default timeout policy.
You should be able to write a piece of middleware that evaluates the criteria you have for session expiration then call set_expiry on the session before processing the request.

Related

How to plug logic into session invalidation due to cookie expiration

In my app, I want to send some request to the api on session invalidation.
I want to be able to differentiate when a user logs out (clicks on the button), and when he is automatically logged out (eg, after inactivity period, cookie expiration...)
I think I've managed most of the use cases, the only remaining one is to be able to 'plug' some logic when the cookie expires, but before the session is cleaned-up.

Django signed cookie session storage, replay attacks, and SESSION_COOKIE_AGE

As per the Django documentation, signed cookie session storage is vulnerable to a replay attack:
Note also that while the MAC can guarantee the authenticity of the
data (that it was generated by your site, and not someone else), and
the integrity of the data (that it is all there and correct), it
cannot guarantee freshness i.e. that you are being sent back the last
thing you sent to the client. This means that for some uses of session
data, the cookie backend might open you up to replay attacks. Unlike
other session backends which keep a server-side record of each session
and invalidate it when a user logs out, cookie-based sessions are not
invalidated when a user logs out. Thus if an attacker steals a user’s
cookie, they can use that cookie to login as that user even if the
user logs out. Cookies will only be detected as ‘stale’ if they are
older than your SESSION_COOKIE_AGE.
Does this mean that:
We are relying on the client-side expiration of cookies to ensure that the session data is destroyed (thus a replay attack is still possible if the cookie contents are captured before the cookie is removed by the browser), or
The server detects the staleness of the data (comparing with SESSION_COOKIE_AGE and explicitly rejects data it deems as stale.
It seems technically possible for Django to be able to determine how 'old' a session is without persisting this data server-side, but the docs don't seem clear about whether or not this is being done, or is Django relying on / trusting the user's browser to kill old cookies (and thus the session could still be replayed if the data was captured prior to its expiry).
Django, through SessionMiddleware, does set the HTTP cookie expiration to SESSION_COOKIE_AGE. This tells the browser when the cookie should be considered "too old" and expired. This is good housekeeping. Also, if the browser detects that a cookie should not be used anymore, it won't use it and this saves Django from spending time examining a cookie can't be used anyway.
However, Django does not rely on the browsers to ensure that expired cookies cannot ever be used again. A rogue agent could get a copy of the cookie and then reuse it past its expiration date. Django prevents this by sending the cookie to the browser formatted like this:
<payload>:<creation stamp>:<signature>
The colons are separators appearing literally in the data. <payload> is the actual session data. <creation stamp> is a time stamp added when the cookie is created, and <signature> is the MAC signature that signs the payload and the creation stamp.
You can see the relevant code in django.core.signing. The comments at the top of the file give you the basic signing scenarios using the Signer class. This class does not know about timestamps. However, when signing cookies, Django uses TimestampSigner, which does know about timestamps and produces the format I've shown above.
When TimestampSigner unsigns a cookie, it checks the timestamp and raises an exception if it is too old:
def unsign(self, value, max_age=None):
"""
Retrieve original value and check it wasn't signed more
than max_age seconds ago.
"""
result = super().unsign(value)
value, timestamp = result.rsplit(self.sep, 1)
timestamp = baseconv.base62.decode(timestamp)
if max_age is not None:
if isinstance(max_age, datetime.timedelta):
max_age = max_age.total_seconds()
# Check timestamp is not older than max_age
age = time.time() - timestamp
if age > max_age:
raise SignatureExpired(
'Signature age %s > %s seconds' % (age, max_age))
return value

Django, setting cookie

Django: Cookie set to expire in 30 seconds is actually expiring in 30 minutes? does
hr = HttpResponse('ok')
hr.set_cookie('user_id', user_id, max_age=30)
while https://stackoverflow.com/a/25179642/433570 does
request.session[user_id] = True
And both says we are setting cookie.
What's the difference between the two?
Can I set the expiration with the request.session method?
In short, cookies are intended to be stored in client side while sessions are stored in server-side (unless you're using cookie based session).
Users can clear http cookies from their browsers but they can't do anything about the sessions on your server. Clearing sessions is up you and your settings. There are some django settings you can use to determine their age like SESSION_COOKIE_AGE. For http cookies it's possible to set attributes like max_age, expires.
Choosing which one to use depends on your requirements; are you going to store sensitive data, is permanence important etc.
References:
Django sessions
Django request-response methods including set_cookie
Wikipedia HTTP cookies

Avoid updating session cookie expire time on request to django

I'm trying to ping Django from a javascript frontend to find out when a user's session will expire. I'm doing this so I can proactively notify a user when their session has expired.
Unfortunately, the session expire time is updated because I'm hitting the Django app. I've tried reading the session cookie from javascript, but it is not accessible (nor recommended to be accessible) from javascript.
How can I ping my Django app from javascript to get when the session will end?
What about passing the number of seconds until session will expire directly to your template/javascript? For example, you can get it using this method in your view function and pass it further.

WSO2 Authentication, adding/modifing timeout to the RememberMe cookie

I am using WSO2 Identity Server 4.1.0 for user authentication.
When using the AuthenticationAdmin, I am able to use the loginWithRememberMeOption to retrieve a 'RememberMe' cookie, for instance:
admin-b55cdc95-a27e-4e3e-9906-76c18b8437c5
I see in the SOAP response that the cookie has a maxAge of 604800. Does this mean that the RememberMe cookie will be unvalidated after 604800ms / 10 mins?
I tried checking the validity of the cookie after 10 minutes by using the loginwithRememberMeCookie operation. But also after 10 minutes, the result was 'true', indicating that the user was still logged in.
Is it possible to add or modify a timeout, so that the session becomes inactive? If so, where can I modify this?
The RememberMe cookie time is in seconds. So, 604800 seconds mean 7 days.
AFAIK, this value cannot be modified.
Session will time out after the session expiry time. You can change the session time out value. But you can still login with remember me cookie.