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:
parent
2a0f4fb5da
commit
e8cff0b8f3
@ -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)
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user