Permalink
Browse files

add host checking and client specific id options

  • Loading branch information...
1 parent 129044a commit a44beb738c2ddbaa069ef97b9aae44ddaf882264 @edcrewe committed Nov 4, 2012
Showing with 58 additions and 24 deletions.
  1. +16 −7 README.txt
  2. +0 −5 cookieless/admin.py
  3. +36 −8 cookieless/middleware.py
  4. +0 −3 cookieless/models.py
  5. +6 −0 cookieless/tests/settings.py
  6. +0 −1 cookieless/views.py
View
23 README.txt
@@ -15,24 +15,24 @@ Django requires cookies to maintain session, and hence for authorisation.
This package is designed to cater for anonymous user session maintenance, without cookies.
WARNING : There are security issues with this, since it is not possible to use
-CSRF protection without either URL rewriting or Cookies to maintain a separate
-token from that posted in the form.
+CSRF protection without session Cookies to maintain a separate token from that passed via the URL or form posts.
-However there are cases when it is required to use forms on a public site, where
-setting cookies is not desirable (due to privacy legislation),
+However there are cases when it is required to use forms on a public site, where setting cookies is not desirable (due to privacy legislation),
nor are complex rewritten URLs.
It is for that purpose this egg was devised.
To ameliorate the security implications, a whitelist of allowed domains or allowed URLs, can be set in the configuration.
+
Usage can also be restricted to SSL only.
-As a final safety measure handling of GET requests can be turned off.
+
+As a final safety measure handling of GET requests can be turned off, so that the encrypted session id is not present in any URLs.
Please NOTE: It is not advisable to use this package without some form of the above restrictions being in place.
The package also provides a decorator utility to turn off cookie setting for particular views (which also sets the csrf_exempt flag).
-The package also handles the case of session handling for users with cookies disabled in the browser.
+The package also handles the case of session handling for anonymous users with cookies disabled in the browser.
Installation
------------
@@ -60,7 +60,16 @@ Rewriting the response automatically rather than use manual <% session_token %>
COOKIELESS_REWRITE = True
-Now you can decorate views to prevent them setting cookies, whilst still retaining the use of Sessions
+Use client ip and user agent to encrypt session key, to add some sort of CSRF protection given the standard CSRF has to be disabled without cookies.
+
+COOKIELESS_CLIENT_ID = True
+
+If this list is populated then only hosts that are specifically whitelisted are allowed to post to the server. So any domains that the site is served over should be added to the list. If no referrer is found, the session is reset.
+This helps protect against XSS attacks.
+
+COOKIELESS_CLIENT_HOSTS = ['localhost', ]
+
+Now you can decorate views to prevent them setting cookies, whilst still retaining the use of Sessions.
Usually this is easiest done in the urls.py of your core application ...
from cookieless.decorators import no_cookies
View
5 cookieless/admin.py
@@ -1,5 +0,0 @@
-from django.contrib import admin
-
-# Add your admin site registrations here, eg.
-# from django-cookieless.models import Author
-# admin.site.register(Author)
View
44 cookieless/middleware.py
@@ -1,6 +1,7 @@
#-*- coding:utf-8 -*-import time
import re, pdb, time
+from urlparse import urlparse
from django.conf import settings
from django.utils.cache import patch_vary_headers
from django.utils.http import cookie_date
@@ -42,9 +43,11 @@ def process_request(self, request):
name = settings.SESSION_COOKIE_NAME
session_key = request.COOKIES.get(name, '')
if not session_key:
- session_key = self._decrypt(request.POST.get(name, None))
+ session_key = self._decrypt(request,
+ request.POST.get(name, None))
if not session_key and getattr(settings, 'COOKIELESS_USE_GET', False):
- session_key = self._decrypt(request.GET.get(name, ''))
+ session_key = self._decrypt(request,
+ request.GET.get(name, ''))
if session_key:
request.COOKIES[name] = session_key
engine = import_module(settings.SESSION_ENGINE)
@@ -90,24 +93,49 @@ def _prepare_url(self, url):
patt = '%s&amp;'
return patt % (url,)
- def _encrypt(self, sessionid):
+ def _encrypt(self, request, sessionid):
""" Avoid showing plain sessionids """
if not sessionid:
return ''
- return crypt(self.secret, sessionid).encode('hex')
+ secret = self._secret(request)
+ return crypt(secret, sessionid).encode('hex')
- def _decrypt(self, sessionid):
- """ Avoid showing plain sessionids """
+ def _decrypt(self, request, sessionid):
+ """ Avoid showing plain sessionids
+ Optionally require that a referer exists and matches the
+ whitelist, or reset the session
+ """
if not sessionid:
return ''
- return crypt(self.secret, sessionid.decode('hex'))
+ secret = self._secret(request)
+ if getattr(settings, 'COOKIELESS_HOSTS', []):
+ referer = request.META.get('HTTP_REFERER', 'None')
+ if referer == 'None':
+ # End session unless a referer is passed
+ return ''
+ url = urlparse(referer)
+ if url.hostname not in settings.COOKIELESS_HOSTS:
+ err = '%s is unauthorised' % url.hostname
+ raise Exception(err)
+ return crypt(secret, sessionid.decode('hex'))
+
+ def _secret(self, request):
+ """ optionally make secret client dependent
+ """
+ if getattr(settings, 'COOKIELESS_CLIENT_ID', False):
+ ip = request.META['REMOTE_ADDR']
+ agent = request.META['HTTP_USER_AGENT']
+ secret = crypt(self.secret, agent + ip)[:16]
+ return secret
+ else:
+ return self.secret
def nocookies_response(self, request, response):
""" Option to rewrite forms and urls to add session automatically """
name = settings.SESSION_COOKIE_NAME
session_key = ''
if request.session.session_key and not request.path.startswith("/admin"):
- session_key = self._encrypt(request.session.session_key)
+ session_key = self._encrypt(request, request.session.session_key)
if type(response) is HttpResponseRedirect:
if not session_key:
View
3 cookieless/models.py
@@ -1,3 +0,0 @@
-from django.db import models
-
-# Create your models here.
View
6 cookieless/tests/settings.py
@@ -6,6 +6,12 @@
COOKIELESS_USE_GET = True
# Rewriting the response automatically rather than use manual <% session_token %> <% session_url %>
COOKIELESS_REWRITE = True
+# Use client ip and browser to encode session key, to add some CSRF protection without being able to use cookies.
+COOKIELESS_CLIENT_ID = True
+
+# If this list is populated then only hosts that are specifically whitelisted# are allowed to post to the server. So any domains that the site is served # over should be added to the list. This helps protect against XSS attacks.
+
+COOKIELESS_HOSTS = ['localhost', ]
DEBUG = True
TEMPLATE_DEBUG = DEBUG
View
1 cookieless/views.py
@@ -1 +0,0 @@
-# Create your views here.

0 comments on commit a44beb7

Please sign in to comment.