Loading django/middleware/csrf.py +1 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from django.utils.http import is_same_domain from django.utils.six.moves import zip 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_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins." Loading docs/ref/csrf.txt +9 −2 Original line number Diff line number Diff line Loading @@ -192,6 +192,8 @@ both is fine, and will incur minimal overhead. If you are using class-based views, you can refer to :ref:`Decorating class-based views<decorating-class-based-views>`. .. _csrf-rejected-requests: Rejected requests ================= Loading @@ -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 :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. .. _how-csrf-works: Loading docs/releases/1.11.txt +3 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,9 @@ Miscellaneous * 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: Features deprecated in 1.11 Loading docs/topics/logging.txt +11 −4 Original line number Diff line number Diff line Loading @@ -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 wish to view all database queries. .. _django-security-logger: ``django.security.*`` ~~~~~~~~~~~~~~~~~~~~~~ The security loggers will receive messages on any occurrence of :exc:`~django.core.exceptions.SuspiciousOperation`. There is a sub-logger for each sub-type of SuspiciousOperation. The level of the log event depends on where the exception is handled. Most occurrences are logged as a warning, while :exc:`~django.core.exceptions.SuspiciousOperation` and other security-related errors. There is a sub-logger for each subtype of security error, including all ``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 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 response, and an error message will be logged to the ``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 to a ``SuspiciousOperation`` will not be logged to the ``django.request`` logger, but only to the ``django.security`` logger. Loading @@ -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`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading tests/csrf_tests/tests.py +25 −14 Original line number Diff line number Diff line Loading @@ -8,12 +8,13 @@ import warnings from django.conf import settings from django.http import HttpRequest, HttpResponse from django.middleware.csrf import ( CSRF_TOKEN_LENGTH, CsrfViewMiddleware, _compare_salted_tokens as equivalent_tokens, get_token, CSRF_TOKEN_LENGTH, REASON_BAD_TOKEN, REASON_NO_CSRF_COOKIE, CsrfViewMiddleware, _compare_salted_tokens as equivalent_tokens, get_token, ) from django.template import RequestContext, Template from django.template.context_processors import csrf from django.test import SimpleTestCase, override_settings from django.test.utils import patch_logger from django.utils.encoding import force_bytes from django.utils.six import text_type from django.views.decorators.csrf import ( Loading Loading @@ -203,18 +204,22 @@ class CsrfViewMiddlewareTest(SimpleTestCase): Check that if no CSRF cookies is present, the middleware rejects the 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() req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) 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): """ Check that if a CSRF cookie is present but no token, the middleware rejects the incoming request. """ with patch_logger('django.security.csrf', 'warning') as logger_calls: req = self._get_POST_csrf_cookie_request() req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) 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): """ Loading Loading @@ -258,13 +263,17 @@ class CsrfViewMiddlewareTest(SimpleTestCase): """ req = TestingHttpRequest() req.method = 'PUT' with patch_logger('django.security.csrf', 'warning') as logger_calls: req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(403, req2.status_code) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) req = TestingHttpRequest() req.method = 'DELETE' with patch_logger('django.security.csrf', 'warning') as logger_calls: req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(403, req2.status_code) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) def test_put_and_delete_allowed(self): """ Loading Loading @@ -681,5 +690,7 @@ class CsrfViewMiddlewareTest(SimpleTestCase): self.assertIsNone(resp) req = CsrfPostRequest(token, raise_error=True) with patch_logger('django.security.csrf', 'warning') as logger_calls: resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(resp.status_code, 403) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_BAD_TOKEN) Loading
django/middleware/csrf.py +1 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from django.utils.http import is_same_domain from django.utils.six.moves import zip 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_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins." Loading
docs/ref/csrf.txt +9 −2 Original line number Diff line number Diff line Loading @@ -192,6 +192,8 @@ both is fine, and will incur minimal overhead. If you are using class-based views, you can refer to :ref:`Decorating class-based views<decorating-class-based-views>`. .. _csrf-rejected-requests: Rejected requests ================= Loading @@ -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 :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. .. _how-csrf-works: Loading
docs/releases/1.11.txt +3 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,9 @@ Miscellaneous * 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: Features deprecated in 1.11 Loading
docs/topics/logging.txt +11 −4 Original line number Diff line number Diff line Loading @@ -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 wish to view all database queries. .. _django-security-logger: ``django.security.*`` ~~~~~~~~~~~~~~~~~~~~~~ The security loggers will receive messages on any occurrence of :exc:`~django.core.exceptions.SuspiciousOperation`. There is a sub-logger for each sub-type of SuspiciousOperation. The level of the log event depends on where the exception is handled. Most occurrences are logged as a warning, while :exc:`~django.core.exceptions.SuspiciousOperation` and other security-related errors. There is a sub-logger for each subtype of security error, including all ``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 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 response, and an error message will be logged to the ``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 to a ``SuspiciousOperation`` will not be logged to the ``django.request`` logger, but only to the ``django.security`` logger. Loading @@ -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`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading
tests/csrf_tests/tests.py +25 −14 Original line number Diff line number Diff line Loading @@ -8,12 +8,13 @@ import warnings from django.conf import settings from django.http import HttpRequest, HttpResponse from django.middleware.csrf import ( CSRF_TOKEN_LENGTH, CsrfViewMiddleware, _compare_salted_tokens as equivalent_tokens, get_token, CSRF_TOKEN_LENGTH, REASON_BAD_TOKEN, REASON_NO_CSRF_COOKIE, CsrfViewMiddleware, _compare_salted_tokens as equivalent_tokens, get_token, ) from django.template import RequestContext, Template from django.template.context_processors import csrf from django.test import SimpleTestCase, override_settings from django.test.utils import patch_logger from django.utils.encoding import force_bytes from django.utils.six import text_type from django.views.decorators.csrf import ( Loading Loading @@ -203,18 +204,22 @@ class CsrfViewMiddlewareTest(SimpleTestCase): Check that if no CSRF cookies is present, the middleware rejects the 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() req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) 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): """ Check that if a CSRF cookie is present but no token, the middleware rejects the incoming request. """ with patch_logger('django.security.csrf', 'warning') as logger_calls: req = self._get_POST_csrf_cookie_request() req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) 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): """ Loading Loading @@ -258,13 +263,17 @@ class CsrfViewMiddlewareTest(SimpleTestCase): """ req = TestingHttpRequest() req.method = 'PUT' with patch_logger('django.security.csrf', 'warning') as logger_calls: req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(403, req2.status_code) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) req = TestingHttpRequest() req.method = 'DELETE' with patch_logger('django.security.csrf', 'warning') as logger_calls: req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(403, req2.status_code) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) def test_put_and_delete_allowed(self): """ Loading Loading @@ -681,5 +690,7 @@ class CsrfViewMiddlewareTest(SimpleTestCase): self.assertIsNone(resp) req = CsrfPostRequest(token, raise_error=True) with patch_logger('django.security.csrf', 'warning') as logger_calls: resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) self.assertEqual(resp.status_code, 403) self.assertEqual(logger_calls[0], 'Forbidden (%s): ' % REASON_BAD_TOKEN)