Django

Code

root/django/branches/newforms-admin/django/contrib/csrf/middleware.py

Revision 6776, 3.6 kB (checked in by jkocherhans, 1 year ago)

newforms-admin: Merged trunk revision [6671].

  • Property svn:eol-style set to native
Line 
1 """
2 Cross Site Request Forgery Middleware.
3
4 This module provides a middleware that implements protection
5 against request forgeries from other sites.
6
7 """
8 from django.conf import settings
9 from django.http import HttpResponseForbidden
10 from django.utils.safestring import mark_safe
11 import md5
12 import re
13 import itertools
14
15 _ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
16
17 _POST_FORM_RE = \
18     re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
19    
20 _HTML_TYPES = ('text/html', 'application/xhtml+xml')   
21
22 def _make_token(session_id):
23     return md5.new(settings.SECRET_KEY + session_id).hexdigest()
24
25 class CsrfMiddleware(object):
26     """Django middleware that adds protection against Cross Site
27     Request Forgeries by adding hidden form fields to POST forms and
28     checking requests for the correct value. 
29     
30     In the list of middlewares, SessionMiddleware is required, and must come
31     after this middleware.  CsrfMiddleWare must come after compression
32     middleware.
33   
34     If a session ID cookie is present, it is hashed with the SECRET_KEY
35     setting to create an authentication token.  This token is added to all
36     outgoing POST forms and is expected on all incoming POST requests that
37     have a session ID cookie.
38     
39     If you are setting cookies directly, instead of using Django's session
40     framework, this middleware will not work.
41     """
42    
43     def process_request(self, request):
44         if request.method == 'POST':
45             try:
46                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
47             except KeyError:
48                 # No session, no check required
49                 return None
50
51             csrf_token = _make_token(session_id)
52             # check incoming token
53             try:
54                 request_csrf_token = request.POST['csrfmiddlewaretoken']
55             except KeyError:
56                 return HttpResponseForbidden(_ERROR_MSG)
57            
58             if request_csrf_token != csrf_token:
59                 return HttpResponseForbidden(_ERROR_MSG)
60                
61         return None
62
63     def process_response(self, request, response):
64         csrf_token = None
65         try:
66             cookie = response.cookies[settings.SESSION_COOKIE_NAME]
67             csrf_token = _make_token(cookie.value)
68         except KeyError:
69             # No outgoing cookie to set session, but
70             # a session might already exist.
71             try:
72                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
73                 csrf_token = _make_token(session_id)
74             except KeyError:
75                 # no incoming or outgoing cookie
76                 pass
77            
78         if csrf_token is not None and \
79                 response['Content-Type'].split(';')[0] in _HTML_TYPES:
80            
81             # ensure we don't add the 'id' attribute twice (HTML validity)
82             idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
83                                             itertools.repeat(''))
84             def add_csrf_field(match):
85                 """Returns the matched <form> tag plus the added <input> element"""
86                 return mark_safe(match.group() + "<div style='display:none;'>" + \
87                 "<input type='hidden' " + idattributes.next() + \
88                 " name='csrfmiddlewaretoken' value='" + csrf_token + \
89                 "' /></div>")
90
91             # Modify any POST forms
92             response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
93         return response
Note: See TracBrowser for help on using the browser.