summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2013-08-21 20:12:19 -0400
committerTim Graham <timograham@gmail.com>2013-08-22 17:55:01 -0400
commit5f061986b9903b335e4bfe41cf172d710604d5cb (patch)
tree9ba64998ced9dcb3519f672a807265bf68c0ca17 /docs
parentbf9382fb02c54a5991fb2eb91322befe21177a49 (diff)
[1.6.x] Fixed #20922 -- Allowed customizing the serializer used by contrib.sessions
Added settings.SESSION_SERIALIZER which is the import path of a serializer to use for sessions. Thanks apollo13, carljm, shaib, akaariai, charettes, and dstufft for reviews. Backport of b0ce6fe656 from master
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/settings.txt26
-rw-r--r--docs/releases/1.6.txt23
-rw-r--r--docs/topics/http/sessions.txt92
3 files changed, 133 insertions, 8 deletions
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 46482b80a6..a137b229dc 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -2392,7 +2392,7 @@ SESSION_ENGINE
Default: ``django.contrib.sessions.backends.db``
-Controls where Django stores session data. Valid values are:
+Controls where Django stores session data. Included engines are:
* ``'django.contrib.sessions.backends.db'``
* ``'django.contrib.sessions.backends.file'``
@@ -2435,6 +2435,30 @@ Whether to save the session data on every request. If this is ``False``
(default), then the session data will only be saved if it has been modified --
that is, if any of its dictionary values have been assigned or deleted.
+.. setting:: SESSION_SERIALIZER
+
+SESSION_SERIALIZER
+------------------
+
+.. versionadded:: 1.5.3
+
+Default: ``'django.contrib.sessions.serializers.JSONSerializer'``
+
+.. versionchanged:: 1.6
+
+ The default switched from
+ :class:`~django.contrib.sessions.serializers.PickleSerializer` to
+ :class:`~django.contrib.sessions.serializers.JSONSerializer` in Django 1.6.
+
+Full import path of a serializer class to use for serializing session data.
+Included serializers are:
+
+* ``'django.contrib.sessions.serializers.PickleSerializer'``
+* ``'django.contrib.sessions.serializers.JSONSerializer'``
+
+See :ref:`session_serialization` for details, including a warning regarding
+possible remote code execution when using
+:class:`~django.contrib.sessions.serializers.PickleSerializer`.
Sites
=====
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index b545cbcd64..105e302b7d 100644
--- a/docs/releases/1.6.txt
+++ b/docs/releases/1.6.txt
@@ -727,6 +727,29 @@ the ``name`` argument so it doesn't conflict with the new url::
You can remove this url pattern after your app has been deployed with Django
1.6 for :setting:`PASSWORD_RESET_TIMEOUT_DAYS`.
+Default session serialization switched to JSON
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Historically, :mod:`django.contrib.sessions` used :mod:`pickle` to serialize
+session data before storing it in the backend. If you're using the :ref:`signed
+cookie session backend<cookie-session-backend>` and :setting:`SECRET_KEY` is
+known by an attacker, the attacker could insert a string into his session
+which, when unpickled, executes arbitrary code on the server. The technique for
+doing so is simple and easily available on the internet. Although the cookie
+session storage signs the cookie-stored data to prevent tampering, a
+:setting:`SECRET_KEY` leak immediately escalates to a remote code execution
+vulnerability.
+
+This attack can be mitigated by serializing session data using JSON rather
+than :mod:`pickle`. To facilitate this, Django 1.5.3 introduced a new setting,
+:setting:`SESSION_SERIALIZER`, to customize the session serialization format.
+For backwards compatibility, this setting defaulted to using :mod:`pickle`
+in Django 1.5.3, but we've changed the default to JSON in 1.6. If you upgrade
+and switch from pickle to JSON, sessions created before the upgrade will be
+lost. While JSON serialization does not support all Python objects like
+:mod:`pickle` does, we highly recommend using JSON-serialized sessions. See the
+:ref:`session_serialization` documentation for more details.
+
Miscellaneous
~~~~~~~~~~~~~
diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt
index 772ee122d5..1dd8c2ae3d 100644
--- a/docs/topics/http/sessions.txt
+++ b/docs/topics/http/sessions.txt
@@ -132,8 +132,9 @@ and the :setting:`SECRET_KEY` setting.
.. warning::
- **If the SECRET_KEY is not kept secret, this can lead to arbitrary remote
- code execution.**
+ **If the SECRET_KEY is not kept secret and you are using the**
+ :class:`~django.contrib.sessions.serializers.PickleSerializer`, **this can
+ lead to arbitrary remote code execution.**
An attacker in possession of the :setting:`SECRET_KEY` can not only
generate falsified session data, which your site will trust, but also
@@ -260,7 +261,9 @@ You can edit it multiple times.
in 5 minutes.
* If ``value`` is a ``datetime`` or ``timedelta`` object, the
- session will expire at that specific date/time.
+ session will expire at that specific date/time. Note that ``datetime``
+ and ``timedelta`` values are only serializable if you are using the
+ :class:`~django.contrib.sessions.serializers.PickleSerializer`.
* If ``value`` is ``0``, the user's session cookie will expire
when the user's Web browser is closed.
@@ -307,6 +310,77 @@ You can edit it multiple times.
Removes expired sessions from the session store. This class method is
called by :djadmin:`clearsessions`.
+.. _session_serialization:
+
+Session serialization
+---------------------
+
+.. versionadded:: 1.5.3
+
+ The ability to customize the session serialization format using the
+ :setting:`SESSION_SERIALIZER` settings was added.
+
+.. versionchanged:: 1.6
+
+Before version 1.6, Django defaulted to using :mod:`pickle` to serialize
+session data before storing it in the backend. If you're using the :ref:`signed
+cookie session backend<cookie-session-backend>` and :setting:`SECRET_KEY` is
+known by an attacker, the attacker could insert a string into his session
+which, when unpickled, executes arbitrary code on the server. The technique for
+doing so is simple and easily available on the internet. Although the cookie
+session storage signs the cookie-stored data to prevent tampering, a
+:setting:`SECRET_KEY` leak immediately escalates to a remote code execution
+vulnerability.
+
+This attack can be mitigated by serializing session data using JSON rather
+than :mod:`pickle`. To facilitate this, Django 1.5.3 introduced a new setting,
+:setting:`SESSION_SERIALIZER`, to customize the session serialization format.
+For backwards compatibility, this setting defaults to
+using :class:`django.contrib.sessions.serializers.PickleSerializer` in
+Django 1.5.x, but, for security hardening, defaults to
+:class:`django.contrib.sessions.serializers.JSONSerializer` in Django 1.6.
+Even with the caveats described in :ref:`custom-serializers`, we highly
+recommend sticking with JSON serialization *especially if you are using the
+cookie backend*.
+
+Bundled Serializers
+^^^^^^^^^^^^^^^^^^^
+
+.. class:: serializers.JSONSerializer
+
+ A wrapper around the JSON serializer from :mod:`django.core.signing`. Can
+ only serialize basic data types. See the :ref:`custom-serializers` section
+ for more details.
+
+.. class:: serializers.PickleSerializer
+
+ Supports arbitrary Python objects, but, as described above, can lead to a
+ remote code execution vulnerability if :setting:`SECRET_KEY` becomes known
+ by an attacker.
+
+.. _custom-serializers:
+
+Write Your Own Serializer
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Note that unlike :class:`~django.contrib.sessions.serializers.PickleSerializer`,
+the :class:`~django.contrib.sessions.serializers.JSONSerializer` cannot handle
+arbitrary Python data types. As is often the case, there is a trade-off between
+convenience and security. If you wish to store more advanced data types
+including ``datetime`` and ``Decimal`` in JSON backed sessions, you will need
+to write a custom serializer (or convert such values to a JSON serializable
+object before storing them in ``request.session``). While serializing these
+values is fairly straightforward
+(``django.core.serializers.json.DateTimeAwareJSONEncoder`` may be helpful),
+writing a decoder that can reliably get back the same thing that you put in is
+more fragile. For example, you run the risk of returning a ``datetime`` that
+was actually a string that just happened to be in the same format chosen for
+``datetime``\s).
+
+Your serializer class must implement two methods,
+``dumps(self, obj)`` and ``loads(self, data)``, to serialize and deserialize
+the dictionary of session data, respectively.
+
Session object guidelines
-------------------------
@@ -396,14 +470,15 @@ An API is available to manipulate session data outside of a view::
>>> from django.contrib.sessions.backends.db import SessionStore
>>> import datetime
>>> s = SessionStore()
- >>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
+ >>> # stored as seconds since epoch since datetimes are not serializable in JSON.
+ >>> s['last_login'] = 1376587691
>>> s.save()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login']
- datetime.datetime(2005, 8, 20, 13, 35, 0)
+ 1376587691
In order to prevent session fixation attacks, sessions keys that don't exist
are regenerated::
@@ -551,8 +626,11 @@ behavior:
Technical details
=================
-* The session dictionary should accept any pickleable Python object. See
- the :mod:`pickle` module for more information.
+* The session dictionary accepts any :mod:`json` serializable value when using
+ :class:`~django.contrib.sessions.serializers.JSONSerializer` or any
+ pickleable Python object when using
+ :class:`~django.contrib.sessions.serializers.PickleSerializer`. See the
+ :mod:`pickle` module for more information.
* Session data is stored in a database table named ``django_session`` .