Opened 4 years ago

Closed 15 months ago

Last modified 15 months ago

#19324 closed Bug (fixed)

invalid session keys cause unnecessary empty records in django_session table

Reported by: liangrubo@… Owned by: nobody
Component: contrib.sessions Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

db session store calls self.create when no record is found for the session key, which causes an empty record inserted. Is this necessary? This gives chance to user to fill the session table with empty records by sending invalid session keys.

is it more appropriate to set session_key to be None in this case?

current implementation:

    def load(self):
        try:
            s = Session.objects.get(
                session_key=self.session_key,
                expire_date__gt=timezone.now()
            )
            return self.decode(s.session_data)
        except (Session.DoesNotExist, SuspiciousOperation):
            self.create()
            return {}

suggested implementation:

    def load(self):
        try:
            s = Session.objects.get(
                session_key=self.session_key,
                expire_date__gt=timezone.now()
            )
            return self.decode(s.session_data)
        except (Session.DoesNotExist, SuspiciousOperation):
            self.session_key = None
            return {}

Change History (7)

comment:1 Changed 4 years ago by Aymeric Augustin

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset
Triage Stage: UnreviewedDesign decision needed

You probably meant: self._session_key = None.

I don't immediately see how this could allow session fixation attacks — but that doesn't prove anything :)

As is, this change causes two test failures:

Creating test database for alias 'default'...
Creating test database for alias 'other'...
........................................................................................x................................................F.............................F..........................................
======================================================================
FAIL: test_save (django.contrib.sessions.tests.DatabaseSessionTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/aaugustin/Documents/dev/django/django/contrib/sessions/tests.py", line 143, in test_save
    self.assertTrue(self.session.exists(self.session.session_key))
AssertionError: False is not true

======================================================================
FAIL: test_save (django.contrib.sessions.tests.DatabaseSessionWithTimeZoneTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/aaugustin/Documents/dev/django/django/contrib/sessions/tests.py", line 143, in test_save
    self.assertTrue(self.session.exists(self.session.session_key))
AssertionError: False is not true

----------------------------------------------------------------------
Ran 210 tests in 0.353s

FAILED (failures=2, expected failures=1)
Destroying test database for alias 'default'...
Destroying test database for alias 'other'...

This could probably be resolved in save(), though.


In fact, this change would cause save() to be called instead of create(). Currently the roles of these two functions overlap: save() even has a must_create argument! See also #18344.

To sum up, the behavior described exists, but it has a very low impact, and even with the proposed change it's easy to cause the cache to fill up. I suspect this ticket should be closed in favor of a ticket describing a refactoring of the sessions API to eliminate the redundancy between save() and create().

comment:2 Changed 4 years ago by Aymeric Augustin

Triage Stage: Design decision neededAccepted

comment:3 Changed 15 months ago by Tim Graham <timograham@…>

Resolution: fixed
Status: newclosed

In 66d12d1a:

[1.8.x] Fixed #19324 -- Avoided creating a session record when loading the session.

The session record is now only created if/when the session is modified. This
prevents a potential DoS via creation of many empty session records.

This is a security fix; disclosure to follow shortly.

comment:4 Changed 15 months ago by Tim Graham <timograham@…>

In df049ed:

Fixed #19324 -- Avoided creating a session record when loading the session.

The session record is now only created if/when the session is modified. This
prevents a potential DoS via creation of many empty session records.

This is a security fix; disclosure to follow shortly.

comment:5 Changed 15 months ago by Tim Graham <timograham@…>

In 2e47f3e:

[1.4.x] Fixed #19324 -- Avoided creating a session record when loading the session.

The session record is now only created if/when the session is modified. This
prevents a potential DoS via creation of many empty session records.

This is a security fix; disclosure to follow shortly.

comment:6 Changed 15 months ago by Tim Graham <timograham@…>

In 1828f43:

[1.7.x] Fixed #19324 -- Avoided creating a session record when loading the session.

The session record is now only created if/when the session is modified. This
prevents a potential DoS via creation of many empty session records.

This is a security fix; disclosure to follow shortly.

comment:7 Changed 15 months ago by Chris Lamb

Now the issue has been disclosed, could the logic be very briefly documented in the code itself? Stripped of context of this security issue, not immediately obvious why — for example — only if session_key is None we want to call .create(), etc. etc.

Note: See TracTickets for help on using tickets.
Back to Top