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):
|
||||
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):
|
||||
# Mechanism to turn off CSRF checks for test suite. It comes after
|
||||
# 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)
|
||||
|
||||
# check incoming token
|
||||
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
||||
# check non-cookie token for match
|
||||
request_csrf_token = ""
|
||||
if request.method == "POST":
|
||||
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
||||
|
||||
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', '')
|
||||
|
||||
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
|
||||
a site with someone else's credentials, is also covered.
|
||||
|
||||
The first defense against CSRF attacks is to ensure that GET requests are
|
||||
side-effect free. POST requests can then be protected by following the steps
|
||||
below.
|
||||
The first defense against CSRF attacks is to ensure that GET requests (and other
|
||||
'safe' methods, as defined by `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_) are
|
||||
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
|
||||
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
||||
|
||||
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.
|
||||
|
||||
3. For all incoming POST requests, a CSRF cookie must be present, and the
|
||||
'csrfmiddlewaretoken' field must be present and correct. If it isn't, the
|
||||
user will get a 403 error.
|
||||
3. For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or
|
||||
TRACE, a CSRF cookie must be present, and the 'csrfmiddlewaretoken' field
|
||||
must be present and correct. If it isn't, the user will get a 403 error.
|
||||
|
||||
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
|
||||
to POST data back.
|
||||
|
||||
It deliberately only targets HTTP POST requests (and the corresponding POST
|
||||
forms). GET requests ought never to have any potentially dangerous side effects
|
||||
(see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET
|
||||
request ought to be harmless.
|
||||
|
||||
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
||||
It deliberately ignores GET requests (and other requests that are defined as
|
||||
'safe' by RFC 2616). These requests ought never to have any potentially
|
||||
dangerous side effects , and so a CSRF attack with a GET request ought to be
|
||||
harmless. RFC 2616 defines POST, PUT and DELETE as 'unsafe', and all other
|
||||
methods are assumed to be unsafe, for maximum protection.
|
||||
|
||||
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
|
||||
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, (), {})
|
||||
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
|
||||
def test_token_node_no_csrf_cookie(self):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue