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
24
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
62
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
70
71 try:
72 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
73 csrf_token = _make_token(session_id)
74 except KeyError:
75
76 pass
77
78 if csrf_token is not None and \
79 response['Content-Type'].split(';')[0] in _HTML_TYPES:
80
81
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
92 response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
93 return response
94