diff options
| author | Jannis Leidel <jannis@leidel.info> | 2011-05-21 14:41:14 +0000 |
|---|---|---|
| committer | Jannis Leidel <jannis@leidel.info> | 2011-05-21 14:41:14 +0000 |
| commit | f60d42846365b2bf2f1c9bc7a3007c303122a20b (patch) | |
| tree | 1fd63d707db2e1ab86dabe762041e1b5cf6a4587 /docs | |
| parent | 15793309e16dcdf5de17594eaef1962a7c35ce31 (diff) | |
Fixed #12417 -- Added signing functionality, including signing cookies. Many thanks to Simon, Stephan, Paul and everyone else involved.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16253 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/index.txt | 1 | ||||
| -rw-r--r-- | docs/ref/request-response.txt | 48 | ||||
| -rw-r--r-- | docs/ref/settings.txt | 13 | ||||
| -rw-r--r-- | docs/releases/1.4.txt | 9 | ||||
| -rw-r--r-- | docs/topics/index.txt | 1 | ||||
| -rw-r--r-- | docs/topics/signing.txt | 135 |
6 files changed, 207 insertions, 0 deletions
diff --git a/docs/index.txt b/docs/index.txt index 9135d32019..8b4ae53bc2 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -171,6 +171,7 @@ Other batteries included * :doc:`Comments <ref/contrib/comments/index>` | :doc:`Moderation <ref/contrib/comments/moderation>` | :doc:`Custom comments <ref/contrib/comments/custom>` * :doc:`Content types <ref/contrib/contenttypes>` * :doc:`Cross Site Request Forgery protection <ref/contrib/csrf>` + * :doc:`Cryptographic signing <topics/signing>` * :doc:`Databrowse <ref/contrib/databrowse>` * :doc:`E-mail (sending) <topics/email>` * :doc:`Flatpages <ref/contrib/flatpages>` diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 6281120d15..d4ff40a746 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -240,6 +240,43 @@ Methods Example: ``"http://example.com/music/bands/the_beatles/?print=true"`` +.. method:: HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) + + .. versionadded:: 1.4 + + Returns a cookie value for a signed cookie, or raises a + :class:`~django.core.signing.BadSignature` exception if the signature is + no longer valid. If you provide the ``default`` argument the exception + will be suppressed and that default value will be returned instead. + + The optional ``salt`` argument can be used to provide extra protection + against brute force attacks on your secret key. If supplied, the + ``max_age`` argument will be checked against the signed timestamp + attached to the cookie value to ensure the cookie is not older than + ``max_age`` seconds. + + For example:: + + >>> request.get_signed_cookie('name') + 'Tony' + >>> request.get_signed_cookie('name', salt='name-salt') + 'Tony' # assuming cookie was set using the same salt + >>> request.get_signed_cookie('non-existing-cookie') + ... + KeyError: 'non-existing-cookie' + >>> request.get_signed_cookie('non-existing-cookie', False) + False + >>> request.get_signed_cookie('cookie-that-was-tampered-with') + ... + BadSignature: ... + >>> request.get_signed_cookie('name', max_age=60) + ... + SignatureExpired: Signature age 1677.3839159 > 60 seconds + >>> request.get_signed_cookie('name', False, max_age=60) + False + + See :doc:`cryptographic signing </topics/signing>` for more information. + .. method:: HttpRequest.is_secure() Returns ``True`` if the request is secure; that is, if it was made with @@ -618,6 +655,17 @@ Methods .. _`cookie Morsel`: http://docs.python.org/library/cookie.html#Cookie.Morsel .. _HTTPOnly: http://www.owasp.org/index.php/HTTPOnly +.. method:: HttpResponse.set_signed_cookie(key, value='', salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False) + + .. versionadded:: 1.4 + + Like :meth:`~HttpResponse.set_cookie()`, but + :doc:`cryptographic signing </topics/signing>` the cookie before setting + it. Use in conjunction with :meth:`HttpRequest.get_signed_cookie`. + You can use the optional ``salt`` argument for added key strength, but + you will need to remember to pass it to the corresponding + :meth:`HttpRequest.get_signed_cookie` call. + .. method:: HttpResponse.delete_cookie(key, path='/', domain=None) Deletes the cookie with the given key. Fails silently if the key doesn't diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index f5f1226f21..4716fabea7 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -1647,6 +1647,19 @@ See :tfilter:`allowed date format strings <date>`. See also ``DATE_FORMAT`` and ``SHORT_DATETIME_FORMAT``. +.. setting:: SIGNING_BACKEND + +SIGNING_BACKEND +--------------- + +.. versionadded:: 1.4 + +Default: 'django.core.signing.TimestampSigner' + +The backend used for signing cookies and other data. + +See also the :doc:`/topics/signing` documentation. + .. setting:: SITE_ID SITE_ID diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 496a4c93d2..a579e96f93 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -46,6 +46,15 @@ not custom filters. This has been rectified with a simple API previously known as "FilterSpec" which was used internally. For more details, see the documentation for :attr:`~django.contrib.admin.ModelAdmin.list_filter`. +Tools for cryptographic signing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Django 1.4 adds both a low-level API for signing values and a high-level API +for setting and reading signed cookies, one of the most common uses of +signing in Web applications. + +See :doc:`cryptographic signing </topics/signing>` docs for more information. + ``reverse_lazy`` ~~~~~~~~~~~~~~~~ diff --git a/docs/topics/index.txt b/docs/topics/index.txt index 49a03befb1..84f9e9f688 100644 --- a/docs/topics/index.txt +++ b/docs/topics/index.txt @@ -18,6 +18,7 @@ Introductions to all the key parts of Django you'll need to know: auth cache conditional-view-processing + signing email i18n/index logging diff --git a/docs/topics/signing.txt b/docs/topics/signing.txt new file mode 100644 index 0000000000..7989643297 --- /dev/null +++ b/docs/topics/signing.txt @@ -0,0 +1,135 @@ +===================== +Cryptographic signing +===================== + +.. module:: django.core.signing + :synopsis: Django's signing framework. + +.. versionadded:: 1.4 + +The golden rule of Web application security is to never trust data from +untrusted sources. Sometimes it can be useful to pass data through an +untrusted medium. Cryptographically signed values can be passed through an +untrusted channel safe in the knowledge that any tampering will be detected. + +Django provides both a low-level API for signing values and a high-level API +for setting and reading signed cookies, one of the most common uses of +signing in Web applications. + +You may also find signing useful for the following: + + * Generating "recover my account" URLs for sending to users who have + lost their password. + + * Ensuring data stored in hidden form fields has not been tampered with. + + * Generating one-time secret URLs for allowing temporary access to a + protected resource, for example a downloadable file that a user has + paid for. + +Protecting the SECRET_KEY +========================= + +When you create a new Django project using :djadmin:`startproject`, the +``settings.py`` file it generates automatically gets a random +:setting:`SECRET_KEY` value. This value is the key to securing signed +data -- it is vital you keep this secure, or attackers could use it to +generate their own signed values. + +Using the low-level API +======================= + +.. class:: Signer + +Django's signing methods live in the ``django.core.signing`` module. +To sign a value, first instantiate a ``Signer`` instance:: + + >>> from django.core.signing import Signer + >>> signer = Signer() + >>> value = signer.sign('My string') + >>> value + 'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w' + +The signature is appended to the end of the string, following the colon. +You can retrieve the original value using the ``unsign`` method:: + + >>> original = signer.unsign(value) + >>> original + u'My string' + +If the signature or value have been altered in any way, a +``django.core.signing.BadSigature`` exception will be raised:: + + >>> value += 'm' + >>> try: + ... original = signer.unsign(value) + ... except signing.BadSignature: + ... print "Tampering detected!" + +By default, the ``Signer`` class uses the :setting:`SECRET_KEY` setting to +generate signatures. You can use a different secret by passing it to the +``Signer`` constructor:: + + >>> signer = Signer('my-other-secret') + >>> value = signer.sign('My string') + >>> value + 'My string:EkfQJafvGyiofrdGnuthdxImIJw' + +Using the salt argument +----------------------- + +If you do not wish to use the same key for every signing operation in your +application, you can use the optional ``salt`` argument to the ``Signer`` +class to further strengthen your :setting:`SECRET_KEY` against brute force +attacks. Using a salt will cause a new key to be derived from both the salt +and your :setting:`SECRET_KEY`:: + + >>> signer = Signer() + >>> signer.sign('My string') + 'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w' + >>> signer = Signer(salt='extra') + >>> signer.sign('My string') + 'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw' + >>> signer.unsign('My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw') + u'My string' + +Unlike your :setting:`SECRET_KEY`, your salt argument does not need to stay +secret. + +Verifying timestamped values +---------------------------- + +.. class:: TimestampSigner + +``TimestampSigner`` is a subclass of :class:`~Signer` that appends a signed +timestamp to the value. This allows you to confirm that a signed value was +created within a specified period of time:: + + >>> from django.core.signing import TimestampSigner + >>> signer = TimestampSigner() + >>> value = signer.sign('hello') + >>> value + 'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c' + >>> signer.unsign(value) + u'hello' + >>> signer.unsign(value, max_age=10) + ... + SignatureExpired: Signature age 15.5289158821 > 10 seconds + >>> signer.unsign(value, max_age=20) + u'hello' + +Protecting complex data structures +---------------------------------- + +If you wish to protect a list, tuple or dictionary you can do so using the +signing module's dumps and loads functions. These imitate Python's pickle +module, but uses JSON serialization under the hood. JSON ensures that even +if your :setting:`SECRET_KEY` is stolen an attacker will not be able to +execute arbitrary commands by exploiting the pickle format.:: + + >>> from django.core import signing + >>> value = signing.dumps({"foo": "bar"}) + >>> value + 'eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI' + >>> signing.loads(value) + {'foo': 'bar'} |
