1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

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.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@13680 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2010-09-03 16:28:10 +00:00
parent 2a0f4fb5da
commit e8cff0b8f3
2 changed files with 33 additions and 8 deletions

View File

@ -27,19 +27,29 @@ else:
randrange = random.randrange randrange = random.randrange
_MAX_CSRF_KEY = 18446744073709551616L # 2 << 63 _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(): def _get_failure_view():
""" """
Returns the view to be used for CSRF rejections Returns the view to be used for CSRF rejections
""" """
return get_callable(settings.CSRF_FAILURE_VIEW) return get_callable(settings.CSRF_FAILURE_VIEW)
def _get_new_csrf_key(): def _get_new_csrf_key():
return md5_constructor("%s%s" return md5_constructor("%s%s"
% (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest() % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
def _make_legacy_session_token(session_id): def _make_legacy_session_token(session_id):
return md5_constructor(settings.SECRET_KEY + session_id).hexdigest() return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
def get_token(request): def get_token(request):
""" """
Returns the the CSRF token required for a POST form. Returns the the CSRF token required for a POST form.
@ -52,6 +62,7 @@ def get_token(request):
request.META["CSRF_COOKIE_USED"] = True request.META["CSRF_COOKIE_USED"] = True
return request.META.get("CSRF_COOKIE", None) return request.META.get("CSRF_COOKIE", None)
class CsrfViewMiddleware(object): class CsrfViewMiddleware(object):
""" """
Middleware that requires a present and correct csrfmiddlewaretoken Middleware that requires a present and correct csrfmiddlewaretoken
@ -143,13 +154,13 @@ class CsrfViewMiddleware(object):
# we can use strict Referer checking. # we can use strict Referer checking.
referer = request.META.get('HTTP_REFERER') referer = request.META.get('HTTP_REFERER')
if referer is None: 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 following check ensures that the referer is HTTPS,
# the domains match and the ports match - the same origin policy. # the domains match and the ports match - the same origin policy.
good_referer = 'https://%s/' % request.get_host() good_referer = 'https://%s/' % request.get_host()
if not referer.startswith(good_referer): if not referer.startswith(good_referer):
return reject("Referer checking failed - %s does not match %s." % return reject(REASON_BAD_REFERER %
(referer, good_referer)) (referer, good_referer))
# If the user didn't already have a CSRF cookie, then fall back to # If the user didn't already have a CSRF cookie, then fall back to
@ -164,7 +175,7 @@ class CsrfViewMiddleware(object):
# No CSRF cookie and no session cookie. For POST requests, # No CSRF cookie and no session cookie. For POST requests,
# we insist on a CSRF cookie, and in this way we can avoid # we insist on a CSRF cookie, and in this way we can avoid
# all CSRF attacks, including login CSRF. # all CSRF attacks, including login CSRF.
return reject("No CSRF or session cookie.") return reject(REASON_NO_COOKIE)
else: else:
csrf_token = request.META["CSRF_COOKIE"] csrf_token = request.META["CSRF_COOKIE"]
@ -173,9 +184,9 @@ class CsrfViewMiddleware(object):
if request_csrf_token != csrf_token: if request_csrf_token != csrf_token:
if cookie_is_new: if cookie_is_new:
# probably a problem setting the CSRF cookie # probably a problem setting the CSRF cookie
return reject("CSRF cookie not set.") return reject(REASON_NO_CSRF_COOKIE)
else: else:
return reject("CSRF token missing or incorrect.") return reject(REASON_BAD_TOKEN)
return accept() return accept()
@ -201,6 +212,7 @@ class CsrfViewMiddleware(object):
response.csrf_processing_done = True response.csrf_processing_done = True
return response return response
class CsrfResponseMiddleware(object): class CsrfResponseMiddleware(object):
""" """
DEPRECATED DEPRECATED
@ -251,6 +263,7 @@ class CsrfResponseMiddleware(object):
del response['ETag'] del response['ETag']
return response return response
class CsrfMiddleware(object): class CsrfMiddleware(object):
""" """
Django middleware that adds protection against Cross Site Django middleware that adds protection against Cross Site
@ -278,4 +291,3 @@ class CsrfMiddleware(object):
def process_view(self, request, callback, callback_args, callback_kwargs): def process_view(self, request, callback, callback_args, callback_kwargs):
return self.view_middleware.process_view(request, callback, callback_args, return self.view_middleware.process_view(request, callback, callback_args,
callback_kwargs) callback_kwargs)

View File

@ -23,7 +23,7 @@ CSRF_FAILRE_TEMPLATE = """
h1 span { font-size:60%; color:#666; font-weight:normal; } h1 span { font-size:60%; color:#666; font-weight:normal; }
#info { background:#f6f6f6; } #info { background:#f6f6f6; }
#info ul { margin: 0.5em 4em; } #info ul { margin: 0.5em 4em; }
#info p { padding-top:10px; } #info p, #summary p { padding-top:10px; }
#summary { background: #ffc; } #summary { background: #ffc; }
#explanation { background:#eee; border-bottom: 0px none; } #explanation { background:#eee; border-bottom: 0px none; }
</style> </style>
@ -32,6 +32,16 @@ CSRF_FAILRE_TEMPLATE = """
<div id="summary"> <div id="summary">
<h1>Forbidden <span>(403)</span></h1> <h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p> <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> </div>
{% if DEBUG %} {% if DEBUG %}
<div id="info"> <div id="info">
@ -83,7 +93,10 @@ def csrf_failure(request, reason=""):
""" """
Default view used when request fails CSRF protection Default view used when request fails CSRF protection
""" """
from django.middleware.csrf import REASON_NO_REFERER
t = Template(CSRF_FAILRE_TEMPLATE) t = Template(CSRF_FAILRE_TEMPLATE)
c = Context({'DEBUG': settings.DEBUG, c = Context({'DEBUG': settings.DEBUG,
'reason': reason}) 'reason': reason,
'no_referer': reason == REASON_NO_REFERER
})
return HttpResponseForbidden(t.render(c), mimetype='text/html') return HttpResponseForbidden(t.render(c), mimetype='text/html')