diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py index 113f658a48..a4480afabf 100644 --- a/django/contrib/sessions/backends/base.py +++ b/django/contrib/sessions/backends/base.py @@ -161,10 +161,27 @@ class SessionBase(object): self._session_key = self._get_new_session_key() return self._session_key + def _validate_session_key(self, key): + """ + Key must be truthy and at least 8 characters long. 8 characters is an + arbitrary lower bound for some minimal key security. + """ + return key and len(key) >= 8 + def _get_session_key(self): - return self._session_key + return self.__session_key + + def _set_session_key(self, value): + """ + Validate session key on assignment. Invalid values will set to None. + """ + if self._validate_session_key(value): + self.__session_key = value + else: + self.__session_key = None session_key = property(_get_session_key) + _session_key = property(_get_session_key, _set_session_key) def _get_session(self, no_load=False): """ diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index 2ee1dae246..afa624e295 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -604,6 +604,8 @@ Miscellaneous `, the empty value is now an empty string instead of ``None``. +* For security hardening, session keys must be at least 8 characters. + .. _deprecated-features-1.9: Features deprecated in 1.9 diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py index 091aea2f72..8a9e98e4a8 100644 --- a/tests/sessions_tests/tests.py +++ b/tests/sessions_tests/tests.py @@ -198,6 +198,21 @@ class SessionTestsMixin(object): # session key; make sure that entry is manually deleted session.delete('1') + def test_session_key_empty_string_invalid(self): + """Falsey values (Such as an empty string) are rejected.""" + self.session._session_key = '' + self.assertIsNone(self.session.session_key) + + def test_session_key_too_short_invalid(self): + """Strings shorter than 8 characters are rejected.""" + self.session._session_key = '1234567' + self.assertIsNone(self.session.session_key) + + def test_session_key_valid_string_saved(self): + """Strings of length 8 and up are accepted and stored.""" + self.session._session_key = '12345678' + self.assertEqual(self.session.session_key, '12345678') + def test_session_key_is_read_only(self): def set_session_key(session): session.session_key = session._get_new_session_key()