mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #31274 -- Used signing infrastructure in SessionBase.encode()/decode().
Thanks Mariusz Felisiak and Florian Apolloner for the reviews.
This commit is contained in:
parent
daaa894960
commit
d4fff711d4
@ -6,6 +6,7 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sessions.exceptions import SuspiciousSession
|
from django.contrib.sessions.exceptions import SuspiciousSession
|
||||||
|
from django.core import signing
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.crypto import (
|
from django.utils.crypto import (
|
||||||
@ -71,6 +72,10 @@ class SessionBase:
|
|||||||
del self._session[key]
|
del self._session[key]
|
||||||
self.modified = True
|
self.modified = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_salt(self):
|
||||||
|
return 'django.contrib.sessions.' + self.__class__.__qualname__
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
return self._session.get(key, default)
|
return self._session.get(key, default)
|
||||||
|
|
||||||
@ -97,16 +102,27 @@ class SessionBase:
|
|||||||
del self[self.TEST_COOKIE_NAME]
|
del self[self.TEST_COOKIE_NAME]
|
||||||
|
|
||||||
def _hash(self, value):
|
def _hash(self, value):
|
||||||
|
# RemovedInDjango40Warning: pre-Django 3.1 format will be invalid.
|
||||||
key_salt = "django.contrib.sessions" + self.__class__.__name__
|
key_salt = "django.contrib.sessions" + self.__class__.__name__
|
||||||
return salted_hmac(key_salt, value).hexdigest()
|
return salted_hmac(key_salt, value).hexdigest()
|
||||||
|
|
||||||
def encode(self, session_dict):
|
def encode(self, session_dict):
|
||||||
"Return the given session dictionary serialized and encoded as a string."
|
"Return the given session dictionary serialized and encoded as a string."
|
||||||
serialized = self.serializer().dumps(session_dict)
|
return signing.dumps(
|
||||||
hash = self._hash(serialized)
|
session_dict, salt=self.key_salt, serializer=self.serializer,
|
||||||
return base64.b64encode(hash.encode() + b":" + serialized).decode('ascii')
|
compress=True,
|
||||||
|
)
|
||||||
|
|
||||||
def decode(self, session_data):
|
def decode(self, session_data):
|
||||||
|
try:
|
||||||
|
return signing.loads(session_data, salt=self.key_salt, serializer=self.serializer)
|
||||||
|
# RemovedInDjango40Warning: when the deprecation ends, handle here
|
||||||
|
# exceptions similar to what _legacy_decode() does now.
|
||||||
|
except Exception:
|
||||||
|
return self._legacy_decode(session_data)
|
||||||
|
|
||||||
|
def _legacy_decode(self, session_data):
|
||||||
|
# RemovedInDjango40Warning: pre-Django 3.1 format will be invalid.
|
||||||
encoded_data = base64.b64decode(session_data.encode('ascii'))
|
encoded_data = base64.b64decode(session_data.encode('ascii'))
|
||||||
try:
|
try:
|
||||||
# could produce ValueError if there is no ':'
|
# could produce ValueError if there is no ':'
|
||||||
|
@ -52,6 +52,8 @@ details on these changes.
|
|||||||
* Support for the pre-Django 3.1 password reset tokens in the admin site (that
|
* Support for the pre-Django 3.1 password reset tokens in the admin site (that
|
||||||
use the SHA-1 hashing algorithm) will be removed.
|
use the SHA-1 hashing algorithm) will be removed.
|
||||||
|
|
||||||
|
* Support for the pre-Django 3.1 encoding format of sessions will be removed.
|
||||||
|
|
||||||
* The ``get_request`` argument for
|
* The ``get_request`` argument for
|
||||||
``django.utils.deprecation.MiddlewareMixin.__init__()`` will be required and
|
``django.utils.deprecation.MiddlewareMixin.__init__()`` will be required and
|
||||||
won't accept ``None``.
|
won't accept ``None``.
|
||||||
|
@ -539,6 +539,10 @@ Miscellaneous
|
|||||||
from the format generated by older versions of Django. Support for the old
|
from the format generated by older versions of Django. Support for the old
|
||||||
format remains until Django 4.0.
|
format remains until Django 4.0.
|
||||||
|
|
||||||
|
* The encoding format of sessions is different from the format generated by
|
||||||
|
older versions of Django. Support for the old format remains until Django
|
||||||
|
4.0.
|
||||||
|
|
||||||
.. _removed-features-3.1:
|
.. _removed-features-3.1:
|
||||||
|
|
||||||
Features removed in 3.1
|
Features removed in 3.1
|
||||||
|
@ -311,6 +311,18 @@ class SessionTestsMixin:
|
|||||||
encoded = self.session.encode(data)
|
encoded = self.session.encode(data)
|
||||||
self.assertEqual(self.session.decode(encoded), data)
|
self.assertEqual(self.session.decode(encoded), data)
|
||||||
|
|
||||||
|
@override_settings(SECRET_KEY='django_tests_secret_key')
|
||||||
|
def test_decode_legacy(self):
|
||||||
|
# RemovedInDjango40Warning: pre-Django 3.1 sessions will be invalid.
|
||||||
|
legacy_encoded = (
|
||||||
|
'OWUzNTNmNWQxNTBjOWExZmM4MmQ3NzNhMDRmMjU4NmYwNDUyNGI2NDp7ImEgdGVzd'
|
||||||
|
'CBrZXkiOiJhIHRlc3QgdmFsdWUifQ=='
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.session.decode(legacy_encoded),
|
||||||
|
{'a test key': 'a test value'},
|
||||||
|
)
|
||||||
|
|
||||||
def test_decode_failure_logged_to_security(self):
|
def test_decode_failure_logged_to_security(self):
|
||||||
bad_encode = base64.b64encode(b'flaskdj:alkdjf').decode('ascii')
|
bad_encode = base64.b64encode(b'flaskdj:alkdjf').decode('ascii')
|
||||||
with self.assertLogs('django.security.SuspiciousSession', 'WARNING') as cm:
|
with self.assertLogs('django.security.SuspiciousSession', 'WARNING') as cm:
|
||||||
|
Loading…
Reference in New Issue
Block a user