1
0
mirror of https://github.com/django/django.git synced 2025-04-01 03:56:42 +00:00

Fixed #26628 -- Changed CSRF logger to django.security.csrf.

This commit is contained in:
Holly Becker 2016-06-02 17:24:48 -07:00 committed by Tim Graham
parent c3495bb984
commit 55fec16aaf
5 changed files with 49 additions and 21 deletions

View File

@ -20,7 +20,7 @@ from django.utils.http import is_same_domain
from django.utils.six.moves import zip from django.utils.six.moves import zip
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
logger = logging.getLogger('django.request') logger = logging.getLogger('django.security.csrf')
REASON_NO_REFERER = "Referer checking failed - no Referer." REASON_NO_REFERER = "Referer checking failed - no Referer."
REASON_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins." REASON_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins."

View File

@ -192,6 +192,8 @@ both is fine, and will incur minimal overhead.
If you are using class-based views, you can refer to If you are using class-based views, you can refer to
:ref:`Decorating class-based views<decorating-class-based-views>`. :ref:`Decorating class-based views<decorating-class-based-views>`.
.. _csrf-rejected-requests:
Rejected requests Rejected requests
================= =================
@ -205,7 +207,12 @@ The error page, however, is not very friendly, so you may want to provide your
own view for handling this condition. To do this, simply set the own view for handling this condition. To do this, simply set the
:setting:`CSRF_FAILURE_VIEW` setting. :setting:`CSRF_FAILURE_VIEW` setting.
CSRF failures are logged as warnings to the :ref:`django-request-logger` CSRF failures are logged as warnings to the :ref:`django.security.csrf
<django-security-logger>` logger.
.. versionchanged:: 1.11
In older versions, CSRF failures are logged to the ``django.request``
logger. logger.
.. _how-csrf-works: .. _how-csrf-works:

View File

@ -246,6 +246,9 @@ Miscellaneous
* Support for SpatiaLite < 4.0 is dropped. * Support for SpatiaLite < 4.0 is dropped.
* CSRF failures are logged to the ``django.security.csrf ``` logger instead of
``django.request``.
.. _deprecated-features-1.11: .. _deprecated-features-1.11:
Features deprecated in 1.11 Features deprecated in 1.11

View File

@ -532,20 +532,23 @@ This logging does not include framework-level initialization (e.g.
``COMMIT``, and ``ROLLBACK``). Turn on query logging in your database if you ``COMMIT``, and ``ROLLBACK``). Turn on query logging in your database if you
wish to view all database queries. wish to view all database queries.
.. _django-security-logger:
``django.security.*`` ``django.security.*``
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
The security loggers will receive messages on any occurrence of The security loggers will receive messages on any occurrence of
:exc:`~django.core.exceptions.SuspiciousOperation`. There is a sub-logger for :exc:`~django.core.exceptions.SuspiciousOperation` and other security-related
each sub-type of SuspiciousOperation. The level of the log event depends on errors. There is a sub-logger for each subtype of security error, including all
where the exception is handled. Most occurrences are logged as a warning, while ``SuspiciousOperation``\s. The level of the log event depends on where the
exception is handled. Most occurrences are logged as a warning, while
any ``SuspiciousOperation`` that reaches the WSGI handler will be logged as an any ``SuspiciousOperation`` that reaches the WSGI handler will be logged as an
error. For example, when an HTTP ``Host`` header is included in a request from error. For example, when an HTTP ``Host`` header is included in a request from
a client that does not match :setting:`ALLOWED_HOSTS`, Django will return a 400 a client that does not match :setting:`ALLOWED_HOSTS`, Django will return a 400
response, and an error message will be logged to the response, and an error message will be logged to the
``django.security.DisallowedHost`` logger. ``django.security.DisallowedHost`` logger.
These log events will reach the 'django' logger by default, which mails error These log events will reach the ``django`` logger by default, which mails error
events to admins when ``DEBUG=False``. Requests resulting in a 400 response due events to admins when ``DEBUG=False``. Requests resulting in a 400 response due
to a ``SuspiciousOperation`` will not be logged to the ``django.request`` to a ``SuspiciousOperation`` will not be logged to the ``django.request``
logger, but only to the ``django.security`` logger. logger, but only to the ``django.security`` logger.
@ -567,6 +570,10 @@ specific logger following this example:
}, },
}, },
Other ``django.security`` loggers not based on ``SuspiciousOperation`` are:
* ``django.security.csrf``: For :ref:`CSRF failures <csrf-rejected-requests>`.
``django.db.backends.schema`` ``django.db.backends.schema``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -8,12 +8,13 @@ import warnings
from django.conf import settings from django.conf import settings
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.middleware.csrf import ( from django.middleware.csrf import (
CSRF_TOKEN_LENGTH, CsrfViewMiddleware, CSRF_TOKEN_LENGTH, REASON_BAD_TOKEN, REASON_NO_CSRF_COOKIE,
_compare_salted_tokens as equivalent_tokens, get_token, CsrfViewMiddleware, _compare_salted_tokens as equivalent_tokens, get_token,
) )
from django.template import RequestContext, Template from django.template import RequestContext, Template
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from django.test.utils import patch_logger
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.six import text_type from django.utils.six import text_type
from django.views.decorators.csrf import ( from django.views.decorators.csrf import (
@ -203,18 +204,22 @@ class CsrfViewMiddlewareTest(SimpleTestCase):
Check that if no CSRF cookies is present, the middleware rejects the Check that if no CSRF cookies is present, the middleware rejects the
incoming request. This will stop login CSRF. incoming request. This will stop login CSRF.
""" """
with patch_logger('django.security.csrf', 'warning') as logger_calls:
req = self._get_POST_no_csrf_cookie_request() req = self._get_POST_no_csrf_cookie_request()
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertEqual(403, req2.status_code) self.assertEqual(403, req2.status_code)
self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE)
def test_process_request_csrf_cookie_no_token(self): def test_process_request_csrf_cookie_no_token(self):
""" """
Check that if a CSRF cookie is present but no token, the middleware Check that if a CSRF cookie is present but no token, the middleware
rejects the incoming request. rejects the incoming request.
""" """
with patch_logger('django.security.csrf', 'warning') as logger_calls:
req = self._get_POST_csrf_cookie_request() req = self._get_POST_csrf_cookie_request()
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertEqual(403, req2.status_code) self.assertEqual(403, req2.status_code)
self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_BAD_TOKEN)
def test_process_request_csrf_cookie_and_token(self): def test_process_request_csrf_cookie_and_token(self):
""" """
@ -258,13 +263,17 @@ class CsrfViewMiddlewareTest(SimpleTestCase):
""" """
req = TestingHttpRequest() req = TestingHttpRequest()
req.method = 'PUT' req.method = 'PUT'
with patch_logger('django.security.csrf', 'warning') as logger_calls:
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertEqual(403, req2.status_code) self.assertEqual(403, req2.status_code)
self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE)
req = TestingHttpRequest() req = TestingHttpRequest()
req.method = 'DELETE' req.method = 'DELETE'
with patch_logger('django.security.csrf', 'warning') as logger_calls:
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertEqual(403, req2.status_code) self.assertEqual(403, req2.status_code)
self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE)
def test_put_and_delete_allowed(self): def test_put_and_delete_allowed(self):
""" """
@ -681,5 +690,7 @@ class CsrfViewMiddlewareTest(SimpleTestCase):
self.assertIsNone(resp) self.assertIsNone(resp)
req = CsrfPostRequest(token, raise_error=True) req = CsrfPostRequest(token, raise_error=True)
with patch_logger('django.security.csrf', 'warning') as logger_calls:
resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertEqual(resp.status_code, 403) self.assertEqual(resp.status_code, 403)
self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_BAD_TOKEN)