Fixed #15258 - Ajax CSRF protection doesn't apply to PUT or DELETE requests
Thanks to brodie for the report, and further input from tow21 This is a potentially backwards incompatible change - if you were doing PUT/DELETE requests and relying on the lack of protection, you will need to update your code, as noted in the releaste notes. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16201 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8cbcf1d3a6
commit
cb060f0f34
|
@ -107,7 +107,8 @@ class CsrfViewMiddleware(object):
|
||||||
if getattr(callback, 'csrf_exempt', False):
|
if getattr(callback, 'csrf_exempt', False):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if request.method == 'POST':
|
# Assume that anything not defined as 'safe' by RC2616 needs protection.
|
||||||
|
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
|
||||||
if getattr(request, '_dont_enforce_csrf_checks', False):
|
if getattr(request, '_dont_enforce_csrf_checks', False):
|
||||||
# Mechanism to turn off CSRF checks for test suite. It comes after
|
# Mechanism to turn off CSRF checks for test suite. It comes after
|
||||||
# the creation of CSRF cookies, so that everything else continues to
|
# the creation of CSRF cookies, so that everything else continues to
|
||||||
|
@ -165,10 +166,14 @@ class CsrfViewMiddleware(object):
|
||||||
)
|
)
|
||||||
return self._reject(request, REASON_NO_CSRF_COOKIE)
|
return self._reject(request, REASON_NO_CSRF_COOKIE)
|
||||||
|
|
||||||
# check incoming token
|
# check non-cookie token for match
|
||||||
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
request_csrf_token = ""
|
||||||
|
if request.method == "POST":
|
||||||
|
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
||||||
|
|
||||||
if request_csrf_token == "":
|
if request_csrf_token == "":
|
||||||
# Fall back to X-CSRFToken, to make things easier for AJAX
|
# Fall back to X-CSRFToken, to make things easier for AJAX,
|
||||||
|
# and possible for PUT/DELETE
|
||||||
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
|
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
|
||||||
|
|
||||||
if not constant_time_compare(request_csrf_token, csrf_token):
|
if not constant_time_compare(request_csrf_token, csrf_token):
|
||||||
|
|
|
@ -13,11 +13,13 @@ who visits the malicious site in their browser. A related type of attack,
|
||||||
'login CSRF', where an attacking site tricks a user's browser into logging into
|
'login CSRF', where an attacking site tricks a user's browser into logging into
|
||||||
a site with someone else's credentials, is also covered.
|
a site with someone else's credentials, is also covered.
|
||||||
|
|
||||||
The first defense against CSRF attacks is to ensure that GET requests are
|
The first defense against CSRF attacks is to ensure that GET requests (and other
|
||||||
side-effect free. POST requests can then be protected by following the steps
|
'safe' methods, as defined by `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_) are
|
||||||
below.
|
side-effect free. Requests via 'unsafe' methods, such as POST, PUT and DELETE,
|
||||||
|
can then be protected by following the steps below.
|
||||||
|
|
||||||
.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
|
.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
|
||||||
|
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
||||||
|
|
||||||
How to use it
|
How to use it
|
||||||
=============
|
=============
|
||||||
|
@ -198,9 +200,9 @@ The CSRF protection is based on the following things:
|
||||||
|
|
||||||
This part is done by the template tag.
|
This part is done by the template tag.
|
||||||
|
|
||||||
3. For all incoming POST requests, a CSRF cookie must be present, and the
|
3. For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or
|
||||||
'csrfmiddlewaretoken' field must be present and correct. If it isn't, the
|
TRACE, a CSRF cookie must be present, and the 'csrfmiddlewaretoken' field
|
||||||
user will get a 403 error.
|
must be present and correct. If it isn't, the user will get a 403 error.
|
||||||
|
|
||||||
This check is done by ``CsrfViewMiddleware``.
|
This check is done by ``CsrfViewMiddleware``.
|
||||||
|
|
||||||
|
@ -215,12 +217,11 @@ The CSRF protection is based on the following things:
|
||||||
This ensures that only forms that have originated from your Web site can be used
|
This ensures that only forms that have originated from your Web site can be used
|
||||||
to POST data back.
|
to POST data back.
|
||||||
|
|
||||||
It deliberately only targets HTTP POST requests (and the corresponding POST
|
It deliberately ignores GET requests (and other requests that are defined as
|
||||||
forms). GET requests ought never to have any potentially dangerous side effects
|
'safe' by RFC 2616). These requests ought never to have any potentially
|
||||||
(see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET
|
dangerous side effects , and so a CSRF attack with a GET request ought to be
|
||||||
request ought to be harmless.
|
harmless. RFC 2616 defines POST, PUT and DELETE as 'unsafe', and all other
|
||||||
|
methods are assumed to be unsafe, for maximum protection.
|
||||||
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
|
||||||
|
|
||||||
Caching
|
Caching
|
||||||
=======
|
=======
|
||||||
|
|
|
@ -214,3 +214,15 @@ you should add the following lines in your settings file::
|
||||||
|
|
||||||
Don't forget to escape characters that have a special meaning in a regular
|
Don't forget to escape characters that have a special meaning in a regular
|
||||||
expression.
|
expression.
|
||||||
|
|
||||||
|
CSRF protection extended to PUT and DELETE
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Previously, Django's :doc:`CSRF protection </ref/contrib/csrf/>` provided
|
||||||
|
protection against only POST requests. Since use of PUT and DELETE methods in
|
||||||
|
AJAX applications is becoming more common, we now protect all methods not
|
||||||
|
defined as safe by RFC 2616 i.e. we exempt GET, HEAD, OPTIONS and TRACE, and
|
||||||
|
enforce protection on everything.
|
||||||
|
|
||||||
|
If you using PUT or DELETE methods in AJAX applications, please see the
|
||||||
|
:ref:`instructions about using AJAX and CSRF <csrf-ajax>`.
|
||||||
|
|
|
@ -164,6 +164,37 @@ class CsrfViewMiddlewareTest(TestCase):
|
||||||
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
||||||
self.assertEqual(None, req2)
|
self.assertEqual(None, req2)
|
||||||
|
|
||||||
|
def test_put_and_delete_rejected(self):
|
||||||
|
"""
|
||||||
|
Tests that HTTP PUT and DELETE methods have protection
|
||||||
|
"""
|
||||||
|
req = TestingHttpRequest()
|
||||||
|
req.method = 'PUT'
|
||||||
|
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
||||||
|
self.assertEqual(403, req2.status_code)
|
||||||
|
|
||||||
|
req = TestingHttpRequest()
|
||||||
|
req.method = 'DELETE'
|
||||||
|
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
||||||
|
self.assertEqual(403, req2.status_code)
|
||||||
|
|
||||||
|
def test_put_and_delete_allowed(self):
|
||||||
|
"""
|
||||||
|
Tests that HTTP PUT and DELETE methods can get through with
|
||||||
|
X-CSRFToken and a cookie
|
||||||
|
"""
|
||||||
|
req = self._get_GET_csrf_cookie_request()
|
||||||
|
req.method = 'PUT'
|
||||||
|
req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
|
||||||
|
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
||||||
|
self.assertEqual(None, req2)
|
||||||
|
|
||||||
|
req = self._get_GET_csrf_cookie_request()
|
||||||
|
req.method = 'DELETE'
|
||||||
|
req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
|
||||||
|
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
|
||||||
|
self.assertEqual(None, req2)
|
||||||
|
|
||||||
# Tests for the template tag method
|
# Tests for the template tag method
|
||||||
def test_token_node_no_csrf_cookie(self):
|
def test_token_node_no_csrf_cookie(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue