Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.2.X] Added explanatory note on CSRF failure page for the case of a…

… missing Referer header.

  
This is intended to help power users who have disabled Referer headers, or
installed add-ons which have done so, and to help web site administrators
with debugging, since this problem will be browser specific and not a
programming error.

Backport of [13680] from trunk. Technically this is a (tiny) new feature,
but it has been backported because it might give significant help with
debugging rare problems with Django 1.2's new CSRF protection.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13682 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 94047d7a3a53d4825d8e9ba1b51022005116ac34 1 parent 7a601b3
Luke Plant spookylukey authored
Showing with 33 additions and 8 deletions.
  1. +18 −6 django/middleware/csrf.py
  2. +15 −2 django/views/csrf.py
24 django/middleware/csrf.py
View
@@ -27,19 +27,29 @@
randrange = random.randrange
_MAX_CSRF_KEY = 18446744073709551616L # 2 << 63
+REASON_NO_REFERER = "Referer checking failed - no Referer."
+REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
+REASON_NO_COOKIE = "No CSRF or session cookie."
+REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
+REASON_BAD_TOKEN = "CSRF token missing or incorrect."
+
+
def _get_failure_view():
"""
Returns the view to be used for CSRF rejections
"""
return get_callable(settings.CSRF_FAILURE_VIEW)
+
def _get_new_csrf_key():
return md5_constructor("%s%s"
% (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
+
def _make_legacy_session_token(session_id):
return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
+
def get_token(request):
"""
Returns the the CSRF token required for a POST form.
@@ -52,6 +62,7 @@ def get_token(request):
request.META["CSRF_COOKIE_USED"] = True
return request.META.get("CSRF_COOKIE", None)
+
class CsrfViewMiddleware(object):
"""
Middleware that requires a present and correct csrfmiddlewaretoken
@@ -129,13 +140,13 @@ def accept():
# Strict referer checking for HTTPS
referer = request.META.get('HTTP_REFERER')
if referer is None:
- return reject("Referer checking failed - no Referer.")
+ return reject(REASON_NO_REFERER)
# The following check ensures that the referer is HTTPS,
# the domains match and the ports match. This might be too strict.
good_referer = 'https://%s/' % request.get_host()
if not referer.startswith(good_referer):
- return reject("Referer checking failed - %s does not match %s." %
+ return reject(REASON_BAD_REFERER %
(referer, good_referer))
# If the user didn't already have a CSRF cookie, then fall back to
@@ -150,7 +161,7 @@ def accept():
# No CSRF cookie and no session cookie. For POST requests,
# we insist on a CSRF cookie, and in this way we can avoid
# all CSRF attacks, including login CSRF.
- return reject("No CSRF or session cookie.")
+ return reject(REASON_NO_COOKIE)
else:
csrf_token = request.META["CSRF_COOKIE"]
@@ -159,9 +170,9 @@ def accept():
if request_csrf_token != csrf_token:
if cookie_is_new:
# probably a problem setting the CSRF cookie
- return reject("CSRF cookie not set.")
+ return reject(REASON_NO_CSRF_COOKIE)
else:
- return reject("CSRF token missing or incorrect.")
+ return reject(REASON_BAD_TOKEN)
return accept()
@@ -187,6 +198,7 @@ def process_response(self, request, response):
response.csrf_processing_done = True
return response
+
class CsrfResponseMiddleware(object):
"""
DEPRECATED
@@ -237,6 +249,7 @@ def add_csrf_field(match):
del response['ETag']
return response
+
class CsrfMiddleware(object):
"""
Django middleware that adds protection against Cross Site
@@ -264,4 +277,3 @@ def process_response(self, request, resp):
def process_view(self, request, callback, callback_args, callback_kwargs):
return self.view_middleware.process_view(request, callback, callback_args,
callback_kwargs)
-
17 django/views/csrf.py
View
@@ -23,7 +23,7 @@
h1 span { font-size:60%; color:#666; font-weight:normal; }
#info { background:#f6f6f6; }
#info ul { margin: 0.5em 4em; }
- #info p { padding-top:10px; }
+ #info p, #summary p { padding-top:10px; }
#summary { background: #ffc; }
#explanation { background:#eee; border-bottom: 0px none; }
</style>
@@ -32,6 +32,16 @@
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
+{% if no_referer %}
+ <p>You are seeing this message because this HTTPS site requires a 'Referer
+ header' to be sent by your web browser, but none was sent. This header is
+ required for security reasons, to ensure that your browser is not being
+ hijacked by third parties.</p>
+
+ <p>If you have configured your browser to disable 'Referer' headers, please
+ re-enable them, at least for this site, or for HTTPS connections, or for
+ 'same-origin' requests.</p>
+{% endif %}
</div>
{% if DEBUG %}
<div id="info">
@@ -83,7 +93,10 @@ def csrf_failure(request, reason=""):
"""
Default view used when request fails CSRF protection
"""
+ from django.middleware.csrf import REASON_NO_REFERER
t = Template(CSRF_FAILRE_TEMPLATE)
c = Context({'DEBUG': settings.DEBUG,
- 'reason': reason})
+ 'reason': reason,
+ 'no_referer': reason == REASON_NO_REFERER
+ })
return HttpResponseForbidden(t.render(c), mimetype='text/html')
Please sign in to comment.
Something went wrong with that request. Please try again.