[Python-modules-commits] [python-django] 01/03: Backport security fixes for DoS in logout() view
Raphaël Hertzog
hertzog at moszumanska.debian.org
Wed Aug 26 16:22:54 UTC 2015
This is an automated email from the git hooks/post-receive script.
hertzog pushed a commit to branch debian/squeeze
in repository python-django.
commit 0eab2654c495db7fc427a6e2ceb4ae36f3c18142
Author: Raphaël Hertzog <hertzog at debian.org>
Date: Wed Aug 26 11:27:15 2015 +0200
Backport security fixes for DoS in logout() view
Backport multiple security fixes released in 1.4 branch:
https://www.djangoproject.com/weblog/2015/aug/18/security-releases/
Denial-of-service possibility in logout() view by filling session store
(CVE-2015-5963 and CVE-2015-5964)
---
debian/changelog | 9 ++
debian/patches/CVE-2015-5963_5964.patch | 193 ++++++++++++++++++++++++++++++++
debian/patches/series | 1 +
3 files changed, 203 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 58730c5..905dd47 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+python-django (1.2.3-3+squeeze14) UNRELEASED; urgency=medium
+
+ * Backport multiple security fixes released in 1.4 branch:
+ https://www.djangoproject.com/weblog/2015/aug/18/security-releases/
+ - Denial-of-service possibility in logout() view by filling session store
+ (CVE-2015-5963 and CVE-2015-5964)
+
+ -- Raphaël Hertzog <hertzog at debian.org> Tue, 25 Aug 2015 14:42:56 +0200
+
python-django (1.2.3-3+squeeze13) squeeze-lts; urgency=medium
* Backport multiple security fixes released in 1.4 branch:
diff --git a/debian/patches/CVE-2015-5963_5964.patch b/debian/patches/CVE-2015-5963_5964.patch
new file mode 100644
index 0000000..4746ab8
--- /dev/null
+++ b/debian/patches/CVE-2015-5963_5964.patch
@@ -0,0 +1,193 @@
+From 575f59f9bc7c59a5e41a081d1f5f55fc859c5012 Mon Sep 17 00:00:00 2001
+From: Tim Graham <timograham at gmail.com>
+Date: Wed, 5 Aug 2015 17:44:48 -0400
+Subject: [PATCH] [1.4.x] Fixed DoS possiblity in contrib.auth.views.logout()
+
+Refs #20936 -- When logging out/ending a session, don't create a new, empty session.
+
+Previously, when logging out, the existing session was overwritten by a
+new sessionid instead of deleting the session altogether.
+
+This behavior added overhead by creating a new session record in
+whichever backend was in use: db, cache, etc.
+
+This extra session is unnecessary at the time since no session data is
+meant to be preserved when explicitly logging out.
+
+Backport of 393c0e24223c701edeb8ce7dc9d0f852f0c081ad,
+088579638b160f3716dc81d194be70c72743593f, and
+2dee853ed4def42b7ef1b3b472b395055543cc00 from master
+
+Thanks Florian Apolloner and Carl Meyer for review.
+
+This is a security fix.
+---
+ django/contrib/sessions/backends/base.py | 9 +++-
+ django/contrib/sessions/backends/cached_db.py | 2 +-
+ django/contrib/sessions/middleware.py | 46 ++++++++++--------
+ django/contrib/sessions/tests.py | 70 +++++++++++++++++++++++++++
+ docs/releases/1.4.22.txt | 18 +++++++
+ docs/topics/http/sessions.txt | 13 +++--
+ 6 files changed, 133 insertions(+), 25 deletions(-)
+
+--- a/django/contrib/sessions/backends/base.py
++++ b/django/contrib/sessions/backends/base.py
+@@ -128,6 +128,13 @@ class SessionBase(object):
+ self.accessed = True
+ self.modified = True
+
++ def is_empty(self):
++ "Returns True when there is no session_key and the session is empty"
++ try:
++ return not bool(self._session_key) and not self._session_cache
++ except AttributeError:
++ return True
++
+ def _get_new_session_key(self):
+ "Returns session key that isn't being used."
+ # The random module is seeded when this Apache child is created.
+@@ -237,7 +244,7 @@ class SessionBase(object):
+ """
+ self.clear()
+ self.delete()
+- self.create()
++ self._session_key = None
+
+ def cycle_key(self):
+ """
+--- a/django/contrib/sessions/backends/cached_db.py
++++ b/django/contrib/sessions/backends/cached_db.py
+@@ -46,4 +46,4 @@ class SessionStore(DBStore):
+ """
+ self.clear()
+ self.delete(self.session_key)
+- self.create()
++ self._session_key = None
+--- a/django/contrib/sessions/middleware.py
++++ b/django/contrib/sessions/middleware.py
+@@ -14,29 +14,38 @@ class SessionMiddleware(object):
+ def process_response(self, request, response):
+ """
+ If request.session was modified, or if the configuration is to save the
+- session every time, save the changes and set a session cookie.
++ session every time, save the changes and set a session cookie or
++ delete the session cookie if the session has been emptied.
+ """
+ try:
+ accessed = request.session.accessed
+ modified = request.session.modified
++ empty = request.session.is_empty()
+ except AttributeError:
+ pass
+ else:
+- if accessed:
+- patch_vary_headers(response, ('Cookie',))
+- if modified or settings.SESSION_SAVE_EVERY_REQUEST:
+- if request.session.get_expire_at_browser_close():
+- max_age = None
+- expires = None
+- else:
+- max_age = request.session.get_expiry_age()
+- expires_time = time.time() + max_age
+- expires = cookie_date(expires_time)
+- # Save the session data and refresh the client cookie.
+- request.session.save()
+- response.set_cookie(settings.SESSION_COOKIE_NAME,
+- request.session.session_key, max_age=max_age,
+- expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
+- path=settings.SESSION_COOKIE_PATH,
+- secure=settings.SESSION_COOKIE_SECURE or None)
++ # First check if we need to delete this cookie.
++ # The session should be deleted only if the session is entirely
++ # empty
++ if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
++ response.delete_cookie(settings.SESSION_COOKIE_NAME,
++ domain=settings.SESSION_COOKIE_DOMAIN)
++ else:
++ if accessed:
++ patch_vary_headers(response, ('Cookie',))
++ if modified or settings.SESSION_SAVE_EVERY_REQUEST:
++ if request.session.get_expire_at_browser_close():
++ max_age = None
++ expires = None
++ else:
++ max_age = request.session.get_expiry_age()
++ expires_time = time.time() + max_age
++ expires = cookie_date(expires_time)
++ # Save the session data and refresh the client cookie.
++ request.session.save()
++ response.set_cookie(settings.SESSION_COOKIE_NAME,
++ request.session.session_key, max_age=max_age,
++ expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
++ path=settings.SESSION_COOKIE_PATH,
++ secure=settings.SESSION_COOKIE_SECURE or None)
+ return response
+--- a/django/contrib/sessions/tests.py
++++ b/django/contrib/sessions/tests.py
+@@ -7,6 +7,9 @@ r"""
+ >>> from django.contrib.sessions.backends.file import SessionStore as FileSession
+ >>> from django.contrib.sessions.backends.base import SessionBase
+ >>> from django.contrib.sessions.models import Session
++>>> from django.contrib.sessions.middleware import SessionMiddleware
++>>> from django.http import HttpResponse
++>>> from django.test import RequestFactory
+
+ >>> db_session = DatabaseSession()
+ >>> db_session.modified
+@@ -36,6 +39,8 @@ True
+ False
+ >>> db_session.session_key == prev_key
+ False
++>>> db_session.session_key
++None
+ >>> db_session.modified, db_session.accessed
+ (True, True)
+ >>> db_session['a'], db_session['b'] = 'c', 'd'
+@@ -139,6 +144,8 @@ True
+ False
+ >>> file_session.session_key == prev_key
+ False
++>>> file_session.session_key
++None
+ >>> file_session.modified, file_session.accessed
+ (True, True)
+ >>> file_session['a'], file_session['b'] = 'c', 'd'
+@@ -442,6 +449,38 @@ True
+ True
+
+ >>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
++
++# Middleware tests
++# Backport of SessionMiddlewareTests.test_session_delete_on_end():
++>>> request = RequestFactory().get('/')
++>>> response = HttpResponse('Session test')
++>>> middleware = SessionMiddleware()
++>>> # Before deleting, there has to be an existing cookie
++>>> request.COOKIES[settings.SESSION_COOKIE_NAME] = 'abc'
++>>> # Simulate a request that ends the session
++>>> middleware.process_request(request)
++>>> request.session.flush()
++>>> # Handle the response through the middleware
++>>> response = middleware.process_response(request, response)
++>>> # Check that the cookie was deleted, not recreated.
++>>> # A deleted cookie header looks like:
++>>> # Set-Cookie: sessionid=; expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/
++>>> 'Set-Cookie: %s=; expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/' % settings.SESSION_COOKIE_NAME == str(response.cookies[settings.SESSION_COOKIE_NAME])
++True
++
++# Backport of
++# SessionMiddlewareTests.test_flush_empty_without_session_cookie_doesnt_set_cookie()
++>>> request = RequestFactory().get('/')
++>>> response = HttpResponse('Session test')
++>>> middleware = SessionMiddleware()
++>>> # Simulate a request that ends the session
++>>> middleware.process_request(request)
++>>> request.session.flush()
++>>> # Handle the response through the middleware
++>>> response = middleware.process_response(request, response)
++>>> response['Vary'] = 'Cookie'
++>>> len(response.cookies)
++0
+ """
+
+ if __name__ == '__main__':
diff --git a/debian/patches/series b/debian/patches/series
index 4bc311d..0c3471c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -44,3 +44,4 @@ CVE-2015-0221-regression-fix.diff
CVE-2015-2317.patch
CVE-2015-5143.patch
CVE-2015-5144.patch
+CVE-2015-5963_5964.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git
More information about the Python-modules-commits
mailing list