Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

add host checking and client specific id options

  • Loading branch information...
commit a44beb738c2ddbaa069ef97b9aae44ddaf882264 1 parent 129044a
Ed Crewe authored
23 README.txt
@@ -15,24 +15,24 @@ Django requires cookies to maintain session, and hence for authorisation.
15 15 This package is designed to cater for anonymous user session maintenance, without cookies.
16 16
17 17 WARNING : There are security issues with this, since it is not possible to use
18   -CSRF protection without either URL rewriting or Cookies to maintain a separate
19   -token from that posted in the form.
  18 +CSRF protection without session Cookies to maintain a separate token from that passed via the URL or form posts.
20 19
21   -However there are cases when it is required to use forms on a public site, where
22   -setting cookies is not desirable (due to privacy legislation),
  20 +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),
23 21 nor are complex rewritten URLs.
24 22
25 23 It is for that purpose this egg was devised.
26 24
27 25 To ameliorate the security implications, a whitelist of allowed domains or allowed URLs, can be set in the configuration.
  26 +
28 27 Usage can also be restricted to SSL only.
29   -As a final safety measure handling of GET requests can be turned off.
  28 +
  29 +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.
30 30
31 31 Please NOTE: It is not advisable to use this package without some form of the above restrictions being in place.
32 32
33 33 The package also provides a decorator utility to turn off cookie setting for particular views (which also sets the csrf_exempt flag).
34 34
35   -The package also handles the case of session handling for users with cookies disabled in the browser.
  35 +The package also handles the case of session handling for anonymous users with cookies disabled in the browser.
36 36
37 37 Installation
38 38 ------------
@@ -60,7 +60,16 @@ Rewriting the response automatically rather than use manual <% session_token %>
60 60
61 61 COOKIELESS_REWRITE = True
62 62
63   -Now you can decorate views to prevent them setting cookies, whilst still retaining the use of Sessions
  63 +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.
  64 +
  65 +COOKIELESS_CLIENT_ID = True
  66 +
  67 +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.
  68 +This helps protect against XSS attacks.
  69 +
  70 +COOKIELESS_CLIENT_HOSTS = ['localhost', ]
  71 +
  72 +Now you can decorate views to prevent them setting cookies, whilst still retaining the use of Sessions.
64 73 Usually this is easiest done in the urls.py of your core application ...
65 74
66 75 from cookieless.decorators import no_cookies
5 cookieless/admin.py
... ... @@ -1,5 +0,0 @@
1   -from django.contrib import admin
2   -
3   -# Add your admin site registrations here, eg.
4   -# from django-cookieless.models import Author
5   -# admin.site.register(Author)
44 cookieless/middleware.py
... ... @@ -1,6 +1,7 @@
1 1 #-*- coding:utf-8 -*-import time
2 2 import re, pdb, time
3 3
  4 +from urlparse import urlparse
4 5 from django.conf import settings
5 6 from django.utils.cache import patch_vary_headers
6 7 from django.utils.http import cookie_date
@@ -42,9 +43,11 @@ def process_request(self, request):
42 43 name = settings.SESSION_COOKIE_NAME
43 44 session_key = request.COOKIES.get(name, '')
44 45 if not session_key:
45   - session_key = self._decrypt(request.POST.get(name, None))
  46 + session_key = self._decrypt(request,
  47 + request.POST.get(name, None))
46 48 if not session_key and getattr(settings, 'COOKIELESS_USE_GET', False):
47   - session_key = self._decrypt(request.GET.get(name, ''))
  49 + session_key = self._decrypt(request,
  50 + request.GET.get(name, ''))
48 51 if session_key:
49 52 request.COOKIES[name] = session_key
50 53 engine = import_module(settings.SESSION_ENGINE)
@@ -90,24 +93,49 @@ def _prepare_url(self, url):
90 93 patt = '%s&amp;'
91 94 return patt % (url,)
92 95
93   - def _encrypt(self, sessionid):
  96 + def _encrypt(self, request, sessionid):
94 97 """ Avoid showing plain sessionids """
95 98 if not sessionid:
96 99 return ''
97   - return crypt(self.secret, sessionid).encode('hex')
  100 + secret = self._secret(request)
  101 + return crypt(secret, sessionid).encode('hex')
98 102
99   - def _decrypt(self, sessionid):
100   - """ Avoid showing plain sessionids """
  103 + def _decrypt(self, request, sessionid):
  104 + """ Avoid showing plain sessionids
  105 + Optionally require that a referer exists and matches the
  106 + whitelist, or reset the session
  107 + """
101 108 if not sessionid:
102 109 return ''
103   - return crypt(self.secret, sessionid.decode('hex'))
  110 + secret = self._secret(request)
  111 + if getattr(settings, 'COOKIELESS_HOSTS', []):
  112 + referer = request.META.get('HTTP_REFERER', 'None')
  113 + if referer == 'None':
  114 + # End session unless a referer is passed
  115 + return ''
  116 + url = urlparse(referer)
  117 + if url.hostname not in settings.COOKIELESS_HOSTS:
  118 + err = '%s is unauthorised' % url.hostname
  119 + raise Exception(err)
  120 + return crypt(secret, sessionid.decode('hex'))
  121 +
  122 + def _secret(self, request):
  123 + """ optionally make secret client dependent
  124 + """
  125 + if getattr(settings, 'COOKIELESS_CLIENT_ID', False):
  126 + ip = request.META['REMOTE_ADDR']
  127 + agent = request.META['HTTP_USER_AGENT']
  128 + secret = crypt(self.secret, agent + ip)[:16]
  129 + return secret
  130 + else:
  131 + return self.secret
104 132
105 133 def nocookies_response(self, request, response):
106 134 """ Option to rewrite forms and urls to add session automatically """
107 135 name = settings.SESSION_COOKIE_NAME
108 136 session_key = ''
109 137 if request.session.session_key and not request.path.startswith("/admin"):
110   - session_key = self._encrypt(request.session.session_key)
  138 + session_key = self._encrypt(request, request.session.session_key)
111 139
112 140 if type(response) is HttpResponseRedirect:
113 141 if not session_key:
3  cookieless/models.py
... ... @@ -1,3 +0,0 @@
1   -from django.db import models
2   -
3   -# Create your models here.
6 cookieless/tests/settings.py
@@ -6,6 +6,12 @@
6 6 COOKIELESS_USE_GET = True
7 7 # Rewriting the response automatically rather than use manual <% session_token %> <% session_url %>
8 8 COOKIELESS_REWRITE = True
  9 +# Use client ip and browser to encode session key, to add some CSRF protection without being able to use cookies.
  10 +COOKIELESS_CLIENT_ID = True
  11 +
  12 +# 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.
  13 +
  14 +COOKIELESS_HOSTS = ['localhost', ]
9 15
10 16 DEBUG = True
11 17 TEMPLATE_DEBUG = DEBUG
1  cookieless/views.py
... ... @@ -1 +0,0 @@
1   -# Create your views here.

0 comments on commit a44beb7

Please sign in to comment.
Something went wrong with that request. Please try again.