In response to some discussion on Chapter 20 of the Django book, I'd
like to submit my first contrib package for consideration, a middleware
package that transparently implements signed cookies. It uses the
SECRET_KEY setting already included in Django, and could easily be
modified to allow different encryption algorithms (currently it simply
uses md5). The only configuration is the addition of the package to
MIDDLEWARE_CLASSES, everything else is handled automatically.

A note on using this with other middlewares. Its position in the
middleware class list defines which other middlewares receive the
security of signed cookies, but there's slightly more to it than that.
In order to ensure that the values passed for further processing are in
fact valid, any cookies not containing a valid signature will be
removed from the HttpRequest instance. For the most part, this is fine,
as long as this middleware is placed before any other middlewares that
use cookies. The only potential advantage to placing a cookie-using
middleware after this one is a savings of 33 characters per cookie,
which can sometimes help, given the length restriction on cookie
values.

However, in the case of SessionMiddleware (and perhaps others), the
value stored is known to just be an ID, and not any actual usable
values. For this case, it's safe to place SessionMiddleware before this
one, and it will work as usual, with the advantage that the 'sessionid'
cookie will not incur the additional 33 characters taken up by the
signing process. However, this also also means that the 'sessionid'
cookie will not be available to any middlewares listed after this one,
nor will it be available in the view. SessionMiddleware stores the
session_key it its own internal structure, so this shouldn't actually
pose any real-world problems. It's just a caveat that should be known
in case it's used with other middlewares where it might cause problems.

The code for middleware.py follows (I've placed it in
django.contrib.signed_cookies, but any other name would suffice):

import re
try:
    from hashlib import md5 as hash
except ImportError:
    from md5 import new as hash

from django.conf import settings

regex = re.compile(r'([0-9a-f]+):(.*)$')

class SignedCookiesMiddleware(object):

    def process_request(self, request):
        for (key, signed_value) in request.COOKIES.items():
            try:
                (signature, value) = regex.match(signed_value).groups()
                assert signature == self.get_digest(key, value)
                request.COOKIES[key] = value
            except:
                del request.COOKIES[key]

    def process_response(self, request, response):
        for (key, morsel) in response.cookies.items():
            if morsel['expires'] == 0 and morsel['max-age'] == 0:
                continue
            digest = self.get_digest(key, morsel.value)
            response.set_cookie(key, '%s:%s' % (digest, morsel.value),
                max_age=morsel['max-age'],
                expires=morsel['expires'],
                path=morsel['path'],
                domain=morsel['domain'],
                secure=morsel['secure']
            )
        return response

    def get_digest(self, key, value):
        string = ':'.join([settings.SECRET_KEY, key, value])
        return hash(string).hexdigest()


--~--~---------~--~----~------------~-------~--~----~
 You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to