Fixed CsrfMiddleware post processing so that it in the presence of multiple

POST <form>s, only one <input> tag is added with an id, for HTML validity.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@2900 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2006-05-11 22:32:47 +00:00
parent c26553c4f9
commit 5c0e4f3908
1 changed files with 16 additions and 8 deletions

View File

@ -9,6 +9,7 @@ from django.conf import settings
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
import md5 import md5
import re import re
import itertools
_ERROR_MSG = "<h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p>" _ERROR_MSG = "<h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p>"
@ -19,7 +20,7 @@ _HTML_TYPES = ('text/html', 'application/xhtml+xml')
def _make_token(session_id): def _make_token(session_id):
return md5.new(settings.SECRET_KEY + session_id).hexdigest() return md5.new(settings.SECRET_KEY + session_id).hexdigest()
class CsrfMiddleware(object): class CsrfMiddleware(object):
"""Django middleware that adds protection against Cross Site """Django middleware that adds protection against Cross Site
Request Forgeries by adding hidden form fields to POST forms and Request Forgeries by adding hidden form fields to POST forms and
@ -57,7 +58,7 @@ class CsrfMiddleware(object):
return HttpResponseForbidden(_ERROR_MSG) return HttpResponseForbidden(_ERROR_MSG)
return None return None
def process_response(self, request, response): def process_response(self, request, response):
csrf_token = None csrf_token = None
try: try:
@ -74,11 +75,18 @@ class CsrfMiddleware(object):
pass pass
if csrf_token is not None and \ if csrf_token is not None and \
response['Content-Type'].split(';')[0] in _HTML_TYPES: response['Content-Type'].split(';')[0] in _HTML_TYPES:
# ensure we don't add the 'id' attribute twice (HTML validity)
idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
itertools.repeat(''))
def add_csrf_field(match):
"""Returns the matched <form> tag plus the added <input> element"""
return match.group() + "<div style='display:none;'>" + \
"<input type='hidden' " + idattributes.next() + \
" name='csrfmiddlewaretoken' value='" + csrf_token + \
"' /></div>"
# Modify any POST forms # Modify any POST forms
extra_field = "<div style='display:none;'>" + \ response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
"<input type='hidden' id='csrfmiddlewaretoken' name='csrfmiddlewaretoken' value='" + \
csrf_token + "' /></div>"
response.content = _POST_FORM_RE.sub('\\1' + extra_field, response.content)
return response return response