2005-08-17 12:00:02 +08:00
|
|
|
|
===================
|
|
|
|
|
How to use sessions
|
|
|
|
|
===================
|
|
|
|
|
|
2009-06-18 21:32:12 +08:00
|
|
|
|
.. module:: django.contrib.sessions
|
|
|
|
|
:synopsis: Provides session management for Django projects.
|
|
|
|
|
|
2011-06-27 01:00:24 +08:00
|
|
|
|
Django provides full support for anonymous sessions. The session framework
|
|
|
|
|
lets you store and retrieve arbitrary data on a per-site-visitor basis. It
|
|
|
|
|
stores data on the server side and abstracts the sending and receiving of
|
|
|
|
|
cookies. Cookies contain a session ID -- not the data itself (unless you're
|
|
|
|
|
using the :ref:`cookie based backend<cookie-session-backend>`).
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
|
|
|
|
Enabling sessions
|
|
|
|
|
=================
|
|
|
|
|
|
2010-08-20 03:27:44 +08:00
|
|
|
|
Sessions are implemented via a piece of :doc:`middleware </ref/middleware>`.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2007-09-16 05:29:14 +08:00
|
|
|
|
To enable session functionality, do the following:
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Edit the :setting:`MIDDLEWARE_CLASSES` setting and make sure
|
|
|
|
|
it contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
|
|
|
|
|
The default ``settings.py`` created by ``django-admin.py startproject``
|
|
|
|
|
has ``SessionMiddleware`` activated.
|
2007-09-16 06:36:53 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
If you don't want to use sessions, you might as well remove the
|
2011-05-30 01:41:04 +08:00
|
|
|
|
``SessionMiddleware`` line from :setting:`MIDDLEWARE_CLASSES` and
|
2011-05-20 08:51:25 +08:00
|
|
|
|
``'django.contrib.sessions'`` from your :setting:`INSTALLED_APPS`.
|
|
|
|
|
It'll save you a small bit of overhead.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2013-01-13 07:44:53 +08:00
|
|
|
|
.. _configuring-sessions:
|
|
|
|
|
|
2007-09-16 05:29:14 +08:00
|
|
|
|
Configuring the session engine
|
|
|
|
|
==============================
|
|
|
|
|
|
|
|
|
|
By default, Django stores sessions in your database (using the model
|
|
|
|
|
``django.contrib.sessions.models.Session``). Though this is convenient, in
|
|
|
|
|
some setups it's faster to store session data elsewhere, so Django can be
|
|
|
|
|
configured to store session data on your filesystem or in your cache.
|
|
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
|
Using database-backed sessions
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
If you want to use a database-backed session, you need to add
|
2011-05-30 01:41:04 +08:00
|
|
|
|
``'django.contrib.sessions'`` to your :setting:`INSTALLED_APPS` setting.
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
2013-07-25 23:19:36 +08:00
|
|
|
|
Once you have configured your installation, run ``manage.py migrate``
|
2009-12-22 23:18:51 +08:00
|
|
|
|
to install the single database table that stores session data.
|
|
|
|
|
|
2012-10-31 04:59:23 +08:00
|
|
|
|
.. _cached-sessions-backend:
|
|
|
|
|
|
2009-01-11 06:18:14 +08:00
|
|
|
|
Using cached sessions
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
For better performance, you may want to use a cache-based session backend.
|
|
|
|
|
|
|
|
|
|
To store session data using Django's cache system, you'll first need to make
|
2010-08-20 03:27:44 +08:00
|
|
|
|
sure you've configured your cache; see the :doc:`cache documentation
|
|
|
|
|
</topics/cache>` for details.
|
2009-01-11 06:18:14 +08:00
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
2009-01-11 13:47:06 +08:00
|
|
|
|
You should only use cache-based sessions if you're using the Memcached
|
|
|
|
|
cache backend. The local-memory cache backend doesn't retain data long
|
|
|
|
|
enough to be a good choice, and it'll be faster to use file or database
|
|
|
|
|
sessions directly instead of sending everything through the file or
|
|
|
|
|
database cache backends.
|
2009-01-11 06:18:14 +08:00
|
|
|
|
|
2012-10-31 04:59:23 +08:00
|
|
|
|
If you have multiple caches defined in :setting:`CACHES`, Django will use the
|
|
|
|
|
default cache. To use another cache, set :setting:`SESSION_CACHE_ALIAS` to the
|
|
|
|
|
name of that cache.
|
|
|
|
|
|
2009-01-11 13:47:06 +08:00
|
|
|
|
Once your cache is configured, you've got two choices for how to store data in
|
2009-01-11 06:18:14 +08:00
|
|
|
|
the cache:
|
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Set :setting:`SESSION_ENGINE` to
|
|
|
|
|
``"django.contrib.sessions.backends.cache"`` for a simple caching session
|
2013-09-20 00:55:09 +08:00
|
|
|
|
store. Session data will be stored directly in your cache. However, session
|
2011-10-14 08:12:01 +08:00
|
|
|
|
data may not be persistent: cached data can be evicted if the cache fills
|
|
|
|
|
up or if the cache server is restarted.
|
2009-01-11 06:18:14 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* For persistent, cached data, set :setting:`SESSION_ENGINE` to
|
|
|
|
|
``"django.contrib.sessions.backends.cached_db"``. This uses a
|
|
|
|
|
write-through cache -- every write to the cache will also be written to
|
|
|
|
|
the database. Session reads only use the database if the data is not
|
|
|
|
|
already in the cache.
|
2009-01-11 06:18:14 +08:00
|
|
|
|
|
|
|
|
|
Both session stores are quite fast, but the simple cache is faster because it
|
2009-01-11 13:47:06 +08:00
|
|
|
|
disregards persistence. In most cases, the ``cached_db`` backend will be fast
|
2009-01-11 06:18:14 +08:00
|
|
|
|
enough, but if you need that last bit of performance, and are willing to let
|
|
|
|
|
session data be expunged from time to time, the ``cache`` backend is for you.
|
|
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
|
If you use the ``cached_db`` session backend, you also need to follow the
|
|
|
|
|
configuration instructions for the `using database-backed sessions`_.
|
|
|
|
|
|
2013-08-30 12:03:23 +08:00
|
|
|
|
.. versionchanged:: 1.7
|
|
|
|
|
|
|
|
|
|
Before version 1.7, the ``cached_db`` backend always used the ``default`` cache
|
|
|
|
|
rather than the :setting:`SESSION_CACHE_ALIAS`.
|
|
|
|
|
|
2007-09-16 05:29:14 +08:00
|
|
|
|
Using file-based sessions
|
|
|
|
|
-------------------------
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
To use file-based sessions, set the :setting:`SESSION_ENGINE` setting to
|
2007-09-16 05:29:14 +08:00
|
|
|
|
``"django.contrib.sessions.backends.file"``.
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
You might also want to set the :setting:`SESSION_FILE_PATH` setting (which
|
|
|
|
|
defaults to output from ``tempfile.gettempdir()``, most likely ``/tmp``) to
|
|
|
|
|
control where Django stores session files. Be sure to check that your Web
|
|
|
|
|
server has permissions to read and write to this location.
|
2007-09-16 05:29:14 +08:00
|
|
|
|
|
2011-06-27 01:00:24 +08:00
|
|
|
|
.. _cookie-session-backend:
|
|
|
|
|
|
|
|
|
|
Using cookie-based sessions
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
To use cookies-based sessions, set the :setting:`SESSION_ENGINE` setting to
|
2011-11-18 05:16:42 +08:00
|
|
|
|
``"django.contrib.sessions.backends.signed_cookies"``. The session data will be
|
2011-06-27 01:00:24 +08:00
|
|
|
|
stored using Django's tools for :doc:`cryptographic signing </topics/signing>`
|
|
|
|
|
and the :setting:`SECRET_KEY` setting.
|
|
|
|
|
|
2013-05-19 00:37:39 +08:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
When using cookies-based sessions :mod:`django.contrib.sessions` can be
|
|
|
|
|
removed from :setting:`INSTALLED_APPS` setting because data is loaded
|
|
|
|
|
from the key itself and not from the database, so there is no need for the
|
|
|
|
|
creation and usage of ``django.contrib.sessions.models.Session`` table.
|
|
|
|
|
|
2011-06-27 01:00:24 +08:00
|
|
|
|
.. note::
|
|
|
|
|
|
2011-11-22 06:03:03 +08:00
|
|
|
|
It's recommended to leave the :setting:`SESSION_COOKIE_HTTPONLY` setting
|
|
|
|
|
``True`` to prevent tampering of the stored data from JavaScript.
|
2011-06-27 01:00:24 +08:00
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
2013-08-22 08:12:19 +08:00
|
|
|
|
**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.**
|
2013-05-18 22:35:39 +08:00
|
|
|
|
|
|
|
|
|
An attacker in possession of the :setting:`SECRET_KEY` can not only
|
|
|
|
|
generate falsified session data, which your site will trust, but also
|
|
|
|
|
remotely execute arbitrary code, as the data is serialized using pickle.
|
|
|
|
|
|
|
|
|
|
If you use cookie-based sessions, pay extra care that your secret key is
|
|
|
|
|
always kept completely secret, for any system which might be remotely
|
|
|
|
|
accessible.
|
|
|
|
|
|
2011-10-17 23:43:24 +08:00
|
|
|
|
**The session data is signed but not encrypted**
|
2011-06-27 01:00:24 +08:00
|
|
|
|
|
2011-10-17 23:43:24 +08:00
|
|
|
|
When using the cookies backend the session data can be read by the client.
|
2011-06-27 01:00:24 +08:00
|
|
|
|
|
2011-10-17 23:43:24 +08:00
|
|
|
|
A MAC (Message Authentication Code) is used to protect the data against
|
|
|
|
|
changes by the client, so that the session data will be invalidated when being
|
|
|
|
|
tampered with. The same invalidation happens if the client storing the
|
|
|
|
|
cookie (e.g. your user's browser) can't store all of the session cookie and
|
|
|
|
|
drops data. Even though Django compresses the data, it's still entirely
|
|
|
|
|
possible to exceed the `common limit of 4096 bytes`_ per cookie.
|
|
|
|
|
|
|
|
|
|
**No freshness guarantee**
|
|
|
|
|
|
|
|
|
|
Note also that while the MAC can guarantee the authenticity of the data
|
|
|
|
|
(that it was generated by your site, and not someone else), and the
|
|
|
|
|
integrity of the data (that it is all there and correct), it cannot
|
|
|
|
|
guarantee freshness i.e. that you are being sent back the last thing you
|
|
|
|
|
sent to the client. This means that for some uses of session data, the
|
2013-10-02 22:15:18 +08:00
|
|
|
|
cookie backend might open you up to `replay attacks`_. Unlike other session
|
|
|
|
|
backends which keep a server-side record of each session and invalidate it
|
|
|
|
|
when a user logs out, cookie-based sessions are not invalidated when a user
|
2013-11-30 21:37:15 +08:00
|
|
|
|
logs out. Thus if an attacker steals a user's cookie, they can use that
|
2013-10-02 22:15:18 +08:00
|
|
|
|
cookie to login as that user even if the user logs out. Cookies will only
|
|
|
|
|
be detected as 'stale' if they are older than your
|
2011-10-17 23:43:24 +08:00
|
|
|
|
:setting:`SESSION_COOKIE_AGE`.
|
|
|
|
|
|
|
|
|
|
**Performance**
|
|
|
|
|
|
|
|
|
|
Finally, the size of a cookie can have an impact on the `speed of your site`_.
|
2011-06-27 01:00:24 +08:00
|
|
|
|
|
|
|
|
|
.. _`common limit of 4096 bytes`: http://tools.ietf.org/html/rfc2965#section-5.3
|
2011-10-17 23:43:24 +08:00
|
|
|
|
.. _`replay attacks`: http://en.wikipedia.org/wiki/Replay_attack
|
2011-06-27 01:00:24 +08:00
|
|
|
|
.. _`speed of your site`: http://yuiblog.com/blog/2007/03/01/performance-research-part-3/
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Using sessions in views
|
|
|
|
|
=======================
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
When ``SessionMiddleware`` is activated, each :class:`~django.http.HttpRequest`
|
|
|
|
|
object -- the first argument to any Django view function -- will have a
|
|
|
|
|
``session`` attribute, which is a dictionary-like object.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
You can read it and write to ``request.session`` at any point in your view.
|
|
|
|
|
You can edit it multiple times.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. class:: backends.base.SessionBase
|
|
|
|
|
|
|
|
|
|
This is the base class for all session objects. It has the following
|
|
|
|
|
standard dictionary methods:
|
|
|
|
|
|
|
|
|
|
.. method:: __getitem__(key)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Example: ``fav_color = request.session['fav_color']``
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. method:: __setitem__(key, value)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Example: ``request.session['fav_color'] = 'blue'``
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. method:: __delitem__(key)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-11-21 01:16:13 +08:00
|
|
|
|
Example: ``del request.session['fav_color']``. This raises ``KeyError``
|
|
|
|
|
if the given ``key`` isn't already in the session.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. method:: __contains__(key)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
|
Example: ``'fav_color' in request.session``
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. method:: get(key, default=None)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Example: ``fav_color = request.session.get('fav_color', 'red')``
|
|
|
|
|
|
2011-08-21 03:22:34 +08:00
|
|
|
|
.. method:: pop(key)
|
|
|
|
|
|
|
|
|
|
Example: ``fav_color = request.session.pop('fav_color')``
|
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: keys()
|
2006-02-11 05:33:07 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: items()
|
2006-02-11 05:33:07 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: setdefault()
|
2007-12-02 23:27:29 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: clear()
|
2008-09-02 11:40:42 +08:00
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
It also has these methods:
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: flush()
|
2008-08-14 11:57:46 +08:00
|
|
|
|
|
2009-05-26 13:29:28 +08:00
|
|
|
|
Delete the current session data from the session and regenerate the
|
2008-08-14 11:57:46 +08:00
|
|
|
|
session key value that is sent back to the user in the cookie. This is
|
|
|
|
|
used if you want to ensure that the previous session data can't be
|
2008-08-14 11:58:00 +08:00
|
|
|
|
accessed again from the user's browser (for example, the
|
2009-02-16 13:10:31 +08:00
|
|
|
|
:func:`django.contrib.auth.logout()` function calls it).
|
2008-08-14 11:57:46 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: set_test_cookie()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Sets a test cookie to determine whether the user's browser supports
|
|
|
|
|
cookies. Due to the way cookies work, you won't be able to test this
|
2008-06-16 12:01:33 +08:00
|
|
|
|
until the user's next page request. See `Setting test cookies`_ below for
|
2005-08-17 12:00:02 +08:00
|
|
|
|
more information.
|
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: test_cookie_worked()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Returns either ``True`` or ``False``, depending on whether the user's
|
|
|
|
|
browser accepted the test cookie. Due to the way cookies work, you'll
|
|
|
|
|
have to call ``set_test_cookie()`` on a previous, separate page request.
|
2008-06-16 12:01:33 +08:00
|
|
|
|
See `Setting test cookies`_ below for more information.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: delete_test_cookie()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2005-09-23 09:28:44 +08:00
|
|
|
|
Deletes the test cookie. Use this to clean up after yourself.
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
.. method:: set_expiry(value)
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
|
|
|
|
Sets the expiration time for the session. You can pass a number of
|
|
|
|
|
different values:
|
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* If ``value`` is an integer, the session will expire after that
|
|
|
|
|
many seconds of inactivity. For example, calling
|
|
|
|
|
``request.session.set_expiry(300)`` would make the session expire
|
|
|
|
|
in 5 minutes.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* If ``value`` is a ``datetime`` or ``timedelta`` object, the
|
2013-08-22 08:12:19 +08:00
|
|
|
|
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`.
|
2008-06-12 11:36:48 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* If ``value`` is ``0``, the user's session cookie will expire
|
|
|
|
|
when the user's Web browser is closed.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* If ``value`` is ``None``, the session reverts to using the global
|
|
|
|
|
session expiry policy.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2010-05-06 09:35:02 +08:00
|
|
|
|
Reading a session is not considered activity for expiration
|
|
|
|
|
purposes. Session expiration is computed from the last time the
|
|
|
|
|
session was *modified*.
|
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: get_expiry_age()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
|
|
|
|
Returns the number of seconds until this session expires. For sessions
|
|
|
|
|
with no custom expiration (or those set to expire at browser close), this
|
2011-05-20 08:51:25 +08:00
|
|
|
|
will equal :setting:`SESSION_COOKIE_AGE`.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2012-10-28 03:32:50 +08:00
|
|
|
|
This function accepts two optional keyword arguments:
|
|
|
|
|
|
|
|
|
|
- ``modification``: last modification of the session, as a
|
|
|
|
|
:class:`~datetime.datetime` object. Defaults to the current time.
|
|
|
|
|
- ``expiry``: expiry information for the session, as a
|
2012-12-29 23:35:12 +08:00
|
|
|
|
:class:`~datetime.datetime` object, an :func:`int` (in seconds), or
|
2012-10-28 03:32:50 +08:00
|
|
|
|
``None``. Defaults to the value stored in the session by
|
|
|
|
|
:meth:`set_expiry`, if there is one, or ``None``.
|
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: get_expiry_date()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
|
|
|
|
Returns the date this session will expire. For sessions with no custom
|
|
|
|
|
expiration (or those set to expire at browser close), this will equal the
|
2011-05-20 08:51:25 +08:00
|
|
|
|
date :setting:`SESSION_COOKIE_AGE` seconds from now.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2013-07-28 09:45:25 +08:00
|
|
|
|
This function accepts the same keyword arguments as :meth:`get_expiry_age`.
|
2012-10-28 03:32:50 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: get_expire_at_browser_close()
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
|
|
|
|
Returns either ``True`` or ``False``, depending on whether the user's
|
2008-06-12 11:36:48 +08:00
|
|
|
|
session cookie will expire when the user's Web browser is closed.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: clear_expired()
|
2012-10-28 05:12:08 +08:00
|
|
|
|
|
|
|
|
|
Removes expired sessions from the session store. This class method is
|
|
|
|
|
called by :djadmin:`clearsessions`.
|
|
|
|
|
|
2014-01-23 05:26:10 +08:00
|
|
|
|
.. method:: cycle_key()
|
2013-09-26 00:59:33 +08:00
|
|
|
|
|
|
|
|
|
Creates a new session key while retaining the current session data.
|
|
|
|
|
:func:`django.contrib.auth.login()` calls this method to mitigate against
|
|
|
|
|
session fixation.
|
|
|
|
|
|
2013-08-22 08:12:19 +08:00
|
|
|
|
.. _session_serialization:
|
|
|
|
|
|
|
|
|
|
Session serialization
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
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
|
2013-09-03 19:48:03 +08:00
|
|
|
|
known by an attacker (there isn't an inherent vulnerability in Django that
|
2013-11-25 11:05:59 +08:00
|
|
|
|
would cause it to leak), the attacker could insert a string into their session
|
2013-08-22 08:12:19 +08:00
|
|
|
|
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
|
2013-09-03 19:48:03 +08:00
|
|
|
|
only serialize basic data types.
|
|
|
|
|
|
|
|
|
|
In addition, as JSON supports only string keys, note that using non-string
|
|
|
|
|
keys in ``request.session`` won't work as expected::
|
|
|
|
|
|
|
|
|
|
>>> # initial assignment
|
|
|
|
|
>>> request.session[0] = 'bar'
|
|
|
|
|
>>> # subsequent requests following serialization & deserialization
|
|
|
|
|
>>> # of session data
|
|
|
|
|
>>> request.session[0] # KeyError
|
|
|
|
|
>>> request.session['0']
|
|
|
|
|
'bar'
|
|
|
|
|
|
|
|
|
|
See the :ref:`custom-serializers` section for more details on limitations
|
|
|
|
|
of JSON serialization.
|
2013-08-22 08:12:19 +08:00
|
|
|
|
|
|
|
|
|
.. 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.
|
|
|
|
|
|
2005-08-17 12:05:42 +08:00
|
|
|
|
Session object guidelines
|
|
|
|
|
-------------------------
|
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Use normal Python strings as dictionary keys on ``request.session``. This
|
|
|
|
|
is more of a convention than a hard-and-fast rule.
|
2005-08-17 12:05:42 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Session dictionary keys that begin with an underscore are reserved for
|
|
|
|
|
internal use by Django.
|
2005-08-17 12:05:42 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Don't override ``request.session`` with a new object, and don't access or
|
|
|
|
|
set its attributes. Use it like a Python dictionary.
|
2005-08-17 12:05:42 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
|
|
|
|
|
This simplistic view sets a ``has_commented`` variable to ``True`` after a user
|
|
|
|
|
posts a comment. It doesn't let a user post a comment more than once::
|
|
|
|
|
|
|
|
|
|
def post_comment(request, new_comment):
|
|
|
|
|
if request.session.get('has_commented', False):
|
|
|
|
|
return HttpResponse("You've already commented.")
|
|
|
|
|
c = comments.Comment(comment=new_comment)
|
|
|
|
|
c.save()
|
|
|
|
|
request.session['has_commented'] = True
|
|
|
|
|
return HttpResponse('Thanks for your comment!')
|
|
|
|
|
|
2005-11-13 12:43:07 +08:00
|
|
|
|
This simplistic view logs in a "member" of the site::
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
|
|
|
|
def login(request):
|
2007-05-03 06:10:12 +08:00
|
|
|
|
m = Member.objects.get(username=request.POST['username'])
|
2005-11-13 12:43:07 +08:00
|
|
|
|
if m.password == request.POST['password']:
|
|
|
|
|
request.session['member_id'] = m.id
|
2005-08-17 12:00:02 +08:00
|
|
|
|
return HttpResponse("You're logged in.")
|
|
|
|
|
else:
|
|
|
|
|
return HttpResponse("Your username and password didn't match.")
|
|
|
|
|
|
2005-11-13 12:43:07 +08:00
|
|
|
|
...And this one logs a member out, according to ``login()`` above::
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
|
|
|
|
def logout(request):
|
|
|
|
|
try:
|
2005-11-13 12:43:07 +08:00
|
|
|
|
del request.session['member_id']
|
2005-08-17 12:00:02 +08:00
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
|
|
|
|
return HttpResponse("You're logged out.")
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
The standard :meth:`django.contrib.auth.logout` function actually does a bit
|
|
|
|
|
more than this to prevent inadvertent data leakage. It calls the
|
|
|
|
|
:meth:`~backends.base.SessionBase.flush` method of ``request.session``.
|
|
|
|
|
We are using this example as a demonstration of how to work with session
|
|
|
|
|
objects, not as a full ``logout()`` implementation.
|
2008-08-14 11:58:00 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Setting test cookies
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
As a convenience, Django provides an easy way to test whether the user's
|
2011-05-20 08:51:25 +08:00
|
|
|
|
browser accepts cookies. Just call the
|
|
|
|
|
:meth:`~backends.base.SessionBase.set_test_cookie` method of
|
|
|
|
|
``request.session`` in a view, and call
|
|
|
|
|
:meth:`~backends.base.SessionBase.test_cookie_worked` in a subsequent view --
|
2005-08-17 12:00:02 +08:00
|
|
|
|
not in the same view call.
|
|
|
|
|
|
|
|
|
|
This awkward split between ``set_test_cookie()`` and ``test_cookie_worked()``
|
|
|
|
|
is necessary due to the way cookies work. When you set a cookie, you can't
|
|
|
|
|
actually tell whether a browser accepted it until the browser's next request.
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
It's good practice to use
|
|
|
|
|
:meth:`~backends.base.SessionBase.delete_test_cookie()` to clean up after
|
|
|
|
|
yourself. Do this after you've verified that the test cookie worked.
|
2005-09-23 09:28:44 +08:00
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Here's a typical usage example::
|
|
|
|
|
|
|
|
|
|
def login(request):
|
2006-11-27 08:08:46 +08:00
|
|
|
|
if request.method == 'POST':
|
2005-08-17 12:00:02 +08:00
|
|
|
|
if request.session.test_cookie_worked():
|
2005-09-23 09:28:44 +08:00
|
|
|
|
request.session.delete_test_cookie()
|
2005-08-17 12:00:02 +08:00
|
|
|
|
return HttpResponse("You're logged in.")
|
|
|
|
|
else:
|
|
|
|
|
return HttpResponse("Please enable cookies and try again.")
|
|
|
|
|
request.session.set_test_cookie()
|
2006-05-02 09:31:56 +08:00
|
|
|
|
return render_to_response('foo/login_form.html')
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
|
|
|
|
Using sessions out of views
|
|
|
|
|
===========================
|
|
|
|
|
|
2013-08-30 02:15:58 +08:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
The examples in this section import the ``SessionStore`` object directly
|
|
|
|
|
from the ``django.contrib.sessions.backends.db`` backend. In your own code,
|
|
|
|
|
you should consider importing ``SessionStore`` from the session engine
|
|
|
|
|
designated by :setting:`SESSION_ENGINE`, as below:
|
|
|
|
|
|
|
|
|
|
>>> from importlib import import_module
|
|
|
|
|
>>> from django.conf import settings
|
|
|
|
|
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
|
|
|
|
|
|
2007-09-16 06:36:53 +08:00
|
|
|
|
An API is available to manipulate session data outside of a view::
|
2007-09-16 05:29:14 +08:00
|
|
|
|
|
2007-09-20 07:32:53 +08:00
|
|
|
|
>>> from django.contrib.sessions.backends.db import SessionStore
|
2012-04-16 00:34:13 +08:00
|
|
|
|
>>> s = SessionStore()
|
2013-08-22 08:12:19 +08:00
|
|
|
|
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
|
|
|
|
|
>>> s['last_login'] = 1376587691
|
2012-04-16 00:34:13 +08:00
|
|
|
|
>>> s.save()
|
|
|
|
|
>>> s.session_key
|
|
|
|
|
'2b1189a188b44ad18c35e113ac6ceead'
|
|
|
|
|
|
|
|
|
|
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
|
2007-09-16 05:29:14 +08:00
|
|
|
|
>>> s['last_login']
|
2013-08-22 08:12:19 +08:00
|
|
|
|
1376587691
|
2007-09-16 05:29:14 +08:00
|
|
|
|
|
2013-09-26 00:59:33 +08:00
|
|
|
|
In order to mitigate session fixation attacks, sessions keys that don't exist
|
2012-04-16 00:34:13 +08:00
|
|
|
|
are regenerated::
|
2010-12-26 04:46:15 +08:00
|
|
|
|
|
|
|
|
|
>>> from django.contrib.sessions.backends.db import SessionStore
|
2012-04-16 00:34:13 +08:00
|
|
|
|
>>> s = SessionStore(session_key='no-such-session-here')
|
2010-12-26 04:46:15 +08:00
|
|
|
|
>>> s.save()
|
|
|
|
|
>>> s.session_key
|
2012-04-16 00:34:13 +08:00
|
|
|
|
'ff882814010ccbc3c870523934fee5a2'
|
2010-12-26 04:46:15 +08:00
|
|
|
|
|
2007-09-20 10:02:21 +08:00
|
|
|
|
If you're using the ``django.contrib.sessions.backends.db`` backend, each
|
2007-09-16 06:36:53 +08:00
|
|
|
|
session is just a normal Django model. The ``Session`` model is defined in
|
|
|
|
|
``django/contrib/sessions/models.py``. Because it's a normal model, you can
|
|
|
|
|
access sessions using the normal Django database API::
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
|
>>> from django.contrib.sessions.models import Session
|
2007-03-26 07:22:04 +08:00
|
|
|
|
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
|
2005-08-17 12:00:02 +08:00
|
|
|
|
>>> s.expire_date
|
2007-09-16 06:36:53 +08:00
|
|
|
|
datetime.datetime(2005, 8, 20, 13, 35, 12)
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
|
|
|
|
Note that you'll need to call ``get_decoded()`` to get the session dictionary.
|
|
|
|
|
This is necessary because the dictionary is stored in an encoded format::
|
|
|
|
|
|
|
|
|
|
>>> s.session_data
|
|
|
|
|
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
|
|
|
|
|
>>> s.get_decoded()
|
|
|
|
|
{'user_id': 42}
|
|
|
|
|
|
2005-11-21 01:16:13 +08:00
|
|
|
|
When sessions are saved
|
|
|
|
|
=======================
|
|
|
|
|
|
|
|
|
|
By default, Django only saves to the session database when the session has been
|
|
|
|
|
modified -- that is if any of its dictionary values have been assigned or
|
|
|
|
|
deleted::
|
|
|
|
|
|
|
|
|
|
# Session is modified.
|
|
|
|
|
request.session['foo'] = 'bar'
|
|
|
|
|
|
|
|
|
|
# Session is modified.
|
|
|
|
|
del request.session['foo']
|
|
|
|
|
|
|
|
|
|
# Session is modified.
|
|
|
|
|
request.session['foo'] = {}
|
|
|
|
|
|
|
|
|
|
# Gotcha: Session is NOT modified, because this alters
|
|
|
|
|
# request.session['foo'] instead of request.session.
|
|
|
|
|
request.session['foo']['bar'] = 'baz'
|
|
|
|
|
|
2007-08-12 18:24:21 +08:00
|
|
|
|
In the last case of the above example, we can tell the session object
|
|
|
|
|
explicitly that it has been modified by setting the ``modified`` attribute on
|
|
|
|
|
the session object::
|
|
|
|
|
|
|
|
|
|
request.session.modified = True
|
|
|
|
|
|
2011-05-20 08:51:25 +08:00
|
|
|
|
To change this default behavior, set the :setting:`SESSION_SAVE_EVERY_REQUEST`
|
|
|
|
|
setting to ``True``. When set to ``True``, Django will save the session to the
|
|
|
|
|
database on every single request.
|
2005-11-02 22:26:55 +08:00
|
|
|
|
|
2005-11-21 01:16:13 +08:00
|
|
|
|
Note that the session cookie is only sent when a session has been created or
|
2011-05-30 01:41:04 +08:00
|
|
|
|
modified. If :setting:`SESSION_SAVE_EVERY_REQUEST` is ``True``, the session
|
|
|
|
|
cookie will be sent on every request.
|
2005-11-21 01:16:13 +08:00
|
|
|
|
|
|
|
|
|
Similarly, the ``expires`` part of a session cookie is updated each time the
|
|
|
|
|
session cookie is sent.
|
|
|
|
|
|
2013-08-19 20:29:32 +08:00
|
|
|
|
The session is not saved if the response's status code is 500.
|
2012-07-05 23:09:48 +08:00
|
|
|
|
|
2013-04-05 00:12:12 +08:00
|
|
|
|
.. _browser-length-vs-persistent-sessions:
|
|
|
|
|
|
2006-06-02 06:25:06 +08:00
|
|
|
|
Browser-length sessions vs. persistent sessions
|
|
|
|
|
===============================================
|
|
|
|
|
|
|
|
|
|
You can control whether the session framework uses browser-length sessions vs.
|
2011-05-20 08:51:25 +08:00
|
|
|
|
persistent sessions with the :setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE`
|
|
|
|
|
setting.
|
2006-06-02 06:25:06 +08:00
|
|
|
|
|
2011-05-30 01:41:04 +08:00
|
|
|
|
By default, :setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE` is set to ``False``,
|
|
|
|
|
which means session cookies will be stored in users' browsers for as long as
|
2011-05-20 08:51:25 +08:00
|
|
|
|
:setting:`SESSION_COOKIE_AGE`. Use this if you don't want people to have to
|
|
|
|
|
log in every time they open a browser.
|
2006-06-02 06:25:06 +08:00
|
|
|
|
|
2011-05-30 01:41:04 +08:00
|
|
|
|
If :setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE` is set to ``True``, Django will
|
|
|
|
|
use browser-length cookies -- cookies that expire as soon as the user closes
|
2013-11-30 21:37:15 +08:00
|
|
|
|
their browser. Use this if you want people to have to log in every time they
|
|
|
|
|
open a browser.
|
2006-06-02 06:25:06 +08:00
|
|
|
|
|
2008-06-08 04:28:06 +08:00
|
|
|
|
This setting is a global default and can be overwritten at a per-session level
|
2011-05-20 08:51:25 +08:00
|
|
|
|
by explicitly calling the :meth:`~backends.base.SessionBase.set_expiry` method
|
|
|
|
|
of ``request.session`` as described above in `using sessions in views`_.
|
2008-06-08 04:28:06 +08:00
|
|
|
|
|
2013-03-02 23:11:23 +08:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
Some browsers (Chrome, for example) provide settings that allow users to
|
|
|
|
|
continue browsing sessions after closing and re-opening the browser. In
|
|
|
|
|
some cases, this can interfere with the
|
|
|
|
|
:setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE` setting and prevent sessions
|
|
|
|
|
from expiring on browser close. Please be aware of this while testing
|
|
|
|
|
Django applications which have the
|
|
|
|
|
:setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE` setting enabled.
|
|
|
|
|
|
2012-10-28 05:12:08 +08:00
|
|
|
|
Clearing the session store
|
2006-12-30 15:30:00 +08:00
|
|
|
|
==========================
|
|
|
|
|
|
2012-10-28 05:12:08 +08:00
|
|
|
|
As users create new sessions on your website, session data can accumulate in
|
|
|
|
|
your session store. If you're using the database backend, the
|
|
|
|
|
``django_session`` database table will grow. If you're using the file backend,
|
|
|
|
|
your temporary directory will contain an increasing number of files.
|
2006-12-30 15:30:00 +08:00
|
|
|
|
|
2012-10-28 05:12:08 +08:00
|
|
|
|
To understand this problem, consider what happens with the database backend.
|
2006-12-30 15:30:00 +08:00
|
|
|
|
When a user logs in, Django adds a row to the ``django_session`` database
|
|
|
|
|
table. Django updates this row each time the session data changes. If the user
|
|
|
|
|
logs out manually, Django deletes the row. But if the user does *not* log out,
|
2012-10-28 05:12:08 +08:00
|
|
|
|
the row never gets deleted. A similar process happens with the file backend.
|
|
|
|
|
|
|
|
|
|
Django does *not* provide automatic purging of expired sessions. Therefore,
|
|
|
|
|
it's your job to purge expired sessions on a regular basis. Django provides a
|
|
|
|
|
clean-up management command for this purpose: :djadmin:`clearsessions`. It's
|
|
|
|
|
recommended to call this command on a regular basis, for example as a daily
|
|
|
|
|
cron job.
|
2006-12-30 15:30:00 +08:00
|
|
|
|
|
2012-10-28 05:12:08 +08:00
|
|
|
|
Note that the cache backend isn't vulnerable to this problem, because caches
|
|
|
|
|
automatically delete stale data. Neither is the cookie backend, because the
|
|
|
|
|
session data is stored by the users' browsers.
|
2006-12-30 15:30:00 +08:00
|
|
|
|
|
2005-11-21 01:16:13 +08:00
|
|
|
|
Settings
|
|
|
|
|
========
|
|
|
|
|
|
2013-01-13 07:44:53 +08:00
|
|
|
|
A few :ref:`Django settings <settings-sessions>` give you control over session
|
2011-05-20 08:51:25 +08:00
|
|
|
|
behavior:
|
2005-11-02 22:26:55 +08:00
|
|
|
|
|
2013-01-13 07:44:53 +08:00
|
|
|
|
* :setting:`SESSION_CACHE_ALIAS`
|
|
|
|
|
* :setting:`SESSION_COOKIE_AGE`
|
|
|
|
|
* :setting:`SESSION_COOKIE_DOMAIN`
|
|
|
|
|
* :setting:`SESSION_COOKIE_HTTPONLY`
|
|
|
|
|
* :setting:`SESSION_COOKIE_NAME`
|
|
|
|
|
* :setting:`SESSION_COOKIE_PATH`
|
|
|
|
|
* :setting:`SESSION_COOKIE_SECURE`
|
|
|
|
|
* :setting:`SESSION_ENGINE`
|
|
|
|
|
* :setting:`SESSION_EXPIRE_AT_BROWSER_CLOSE`
|
|
|
|
|
* :setting:`SESSION_FILE_PATH`
|
|
|
|
|
* :setting:`SESSION_SAVE_EVERY_REQUEST`
|
2005-11-02 22:26:55 +08:00
|
|
|
|
|
2013-09-26 00:59:33 +08:00
|
|
|
|
.. _topics-session-security:
|
|
|
|
|
|
|
|
|
|
Session security
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
Subdomains within a site are able to set cookies on the client for the whole
|
2014-01-04 01:02:58 +08:00
|
|
|
|
domain. This makes session fixation possible if cookies are permitted from
|
|
|
|
|
subdomains not controlled by trusted users.
|
2013-09-26 00:59:33 +08:00
|
|
|
|
|
|
|
|
|
For example, an attacker could log into ``good.example.com`` and get a valid
|
2013-11-25 11:05:59 +08:00
|
|
|
|
session for their account. If the attacker has control over ``bad.example.com``,
|
|
|
|
|
they can use it to send their session key to you since a subdomain is permitted
|
2013-11-19 08:10:58 +08:00
|
|
|
|
to set cookies on ``*.example.com``. When you visit ``good.example.com``,
|
2013-09-26 00:59:33 +08:00
|
|
|
|
you'll be logged in as the attacker and might inadvertently enter your
|
|
|
|
|
sensitive personal data (e.g. credit card info) into the attackers account.
|
|
|
|
|
|
|
|
|
|
Another possible attack would be if ``good.example.com`` sets its
|
|
|
|
|
:setting:`SESSION_COOKIE_DOMAIN` to ``".example.com"`` which would cause
|
|
|
|
|
session cookies from that site to be sent to ``bad.example.com``.
|
|
|
|
|
|
2005-08-17 12:00:02 +08:00
|
|
|
|
Technical details
|
|
|
|
|
=================
|
|
|
|
|
|
2013-08-22 08:12:19 +08:00
|
|
|
|
* 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.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Session data is stored in a database table named ``django_session`` .
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
|
* Django only sends a cookie if it needs to. If you don't set any session
|
|
|
|
|
data, it won't send a session cookie.
|
2005-08-17 12:00:02 +08:00
|
|
|
|
|
2005-11-02 22:26:55 +08:00
|
|
|
|
Session IDs in URLs
|
|
|
|
|
===================
|
|
|
|
|
|
|
|
|
|
The Django sessions framework is entirely, and solely, cookie-based. It does
|
|
|
|
|
not fall back to putting session IDs in URLs as a last resort, as PHP does.
|
|
|
|
|
This is an intentional design decision. Not only does that behavior make URLs
|
|
|
|
|
ugly, it makes your site vulnerable to session-ID theft via the "Referer"
|
|
|
|
|
header.
|