#18194: File-based session never expire ----------------------------------+------------------------------------- Reporter: ej | Owner: aaugustin Type: Bug | Status: new Component: contrib.sessions | Version: master Severity: Release blocker | Resolution: Keywords: | Triage Stage: Accepted Has patch: 1 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 ----------------------------------+-------------------------------------
Comment (by aaugustin): I've worked on this ticket today. Here's an analysis of how session expiration is handled by django.contrib.sessions, and specifically by the built-in backends. Expiration is handled both client-side (by setting cookie expiry) and server-side (because we don't want to keep stale data forever). This ticket is about synchronizing server-side expiration with client-side expiration, especially for the file backend. Historically Django hasn't paid much attention to server-side expiration. ---- The default session expiration policy is: - client-side: expire after `settings.SESSION_COOKIE_AGE` seconds if `settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False` (default), at browser close otherwise - server-side: expire after `settings.SESSION_COOKIE_AGE` (no matter the value of `settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False`) When a non-default expiration is set with `session.set_expiry(...)`, it is saved in the session under the `_session_expiry` key. The semantic of this value is: - if it's missing or `None`: use the default expiration policy described above - if it's `0`: expire at browser close (client side), after `settings.SESSION_COOKIE_AGE` (server side) - if it's an `int`: expire in that many seconds (both sides) - if it's a `datetime`: expire at that time (both sides) This analysis is based on the implementation of `SessionMiddleware`, `session.get_expire_at_browser_close()`, `session.get_expiry_age()` (which controls client-side expiry) and `session.get_expiry_date()` (which controls server-side expiry). '''tl;dr''' The expiry date of a session is always defined by `session.get_expiry_date()` / `session.get_expiry_age()` '''at the time the session is saved''' — because it relies on `timezone.now()` in some cases. ---- How do the various backends deal with that? - '''cache''': the expiry age is computed and passed to the cache engine. The cache engine is responsible for not returning stale data. Since correct expiry is a major feature for a cache, I think we can rely on cache engine to enforce expiry properly. There's no need to clear expired sessions, the cache does it by itself. - '''cached_db''': there's a bug here — expiry age is hardcoded to `settings.SESSION_COOKIE_AGE` instead of `session.get_expiry_age()`. Otherwise it should work like '''cache''' and '''db'''. - '''db''': the session expiry date is computed and stored alongside the session data when the session is saved. Only sessions whose expiry dates are in the future can be re-loaded. Sessions whose expiry dates are in the past can be cleared. - '''file''': the session expiry date isn't stored. It can be rebuilt with the algorithm of `session.get_expiry_age()`, by substituting the file's last modification time to `timezone.now()`. The patches above attempt to do that in order to clear expired sessions. - '''signed_cookies''': server-side expiration is provided by timestamping and signing the cookies. However non-default expiry dates aren't handled; the maximum expiration time is hardcoded at `settings.SESSION_COOKIE_AGE`. There's no need to clear expired sessions because they're stored client- side. ---- That was a bit long but necessary to frame this ticket :) Now there are two actions: 1) Clear expired sessions with the file backend. The patches above are on the right track. This depends on #18978. 2) In the longer term, always store the expiration date in the session and refuse to load an expired session in `SessionBase.load`. This is already how signed cookies work. It overlaps significantly with `_session_expiry` as described above. It's a major refactor of `django.contrib.sessions` that will require backwards-compatibility. Since 1.5 is now feature-frozen, let's restrict this ticket to 1) and create a new ticket for 2). -- Ticket URL: <https://code.djangoproject.com/ticket/18194#comment:12> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To post to this group, send email to django-updates@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.