diff options
| -rw-r--r-- | docs/narr/sessions.rst | 9 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 9 | ||||
| -rw-r--r-- | docs/whatsnew-1.7.rst | 4 | ||||
| -rw-r--r-- | pyramid/tests/test_viewderivers.py | 11 | ||||
| -rw-r--r-- | pyramid/viewderivers.py | 4 |
5 files changed, 26 insertions, 11 deletions
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index ad086268b..0e895ff81 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -411,15 +411,16 @@ Checking CSRF Tokens Automatically .. versionadded:: 1.7 -:app:`Pyramid` supports automatically checking CSRF tokens on POST requests. -Any other request may be checked manually. This feature can be turned on -globally for an application using the ``pyramid.require_default_csrf`` setting. +:app:`Pyramid` supports automatically checking CSRF tokens on requests with an +unsafe method as defined by RFC2616. Any other request may be checked manually. +This feature can be turned on globally for an application using the +``pyramid.require_default_csrf`` setting. If the ``pyramid.required_default_csrf`` setting is a :term:`truthy string` or ``True`` then the default CSRF token parameter will be ``csrf_token``. If a different token is desired, it may be passed as the value. Finally, a :term:`falsey string` or ``False`` will turn off automatic CSRF checking -globally on every POST request. +globally on every request. No matter what, CSRF checking may be explicitly enabled or disabled on a per-view basis using the ``require_csrf`` view option. This option is of the diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 40db5fbeb..3b8f0353a 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -195,10 +195,11 @@ Non-Predicate Arguments ``require_csrf`` - CSRF checks only affect POST requests. Any other request methods will pass - untouched. This option is used in combination with the - ``pyramid.require_default_csrf`` setting to control which request parameters - are checked for CSRF tokens. + CSRF checks will affect any request method that is not defined as a "safe" + method by RFC2616. In pratice this means that GET, HEAD, OPTIONS, and TRACE + methods will pass untouched and all others methods will require CSRF. This + option is used in combination with the ``pyramid.require_default_csrf`` + setting to control which request parameters are checked for CSRF tokens. This feature requires a configured :term:`session factory`. diff --git a/docs/whatsnew-1.7.rst b/docs/whatsnew-1.7.rst index 83ece690e..b85e65ec1 100644 --- a/docs/whatsnew-1.7.rst +++ b/docs/whatsnew-1.7.rst @@ -39,14 +39,14 @@ Feature Additions to security checks. See https://github.com/Pylons/pyramid/pull/2021 - Added a new setting, ``pyramid.require_default_csrf`` which may be used - to turn on CSRF checks globally for every POST request in the application. + to turn on CSRF checks globally for every request in the application. This should be considered a good default for websites built on Pyramid. It is possible to opt-out of CSRF checks on a per-view basis by setting ``require_csrf=False`` on those views. See :ref:`auto_csrf_checking` and https://github.com/Pylons/pyramid/pull/2413 -- Added a ``require_csrf`` view option which will enforce CSRF checks on POST +- Added a ``require_csrf`` view option which will enforce CSRF checks on requests. If the CSRF check fails a ``BadCSRFToken`` exception will be raised and may be caught by exception views (the default response is a ``400 Bad Request``). This option should be used in place of the deprecated diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index bd5b3f2de..4613762f5 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -1170,6 +1170,17 @@ class TestDeriveView(unittest.TestCase): view = self.config._derive_view(inner_view, require_csrf='DUMMY') self.assertRaises(BadCSRFToken, lambda: view(None, request)) + def test_csrf_view_fails_on_bad_PUT_header(self): + from pyramid.exceptions import BadCSRFToken + def inner_view(request): pass + request = self._makeRequest() + request.method = 'PUT' + request.POST = {} + request.session = DummySession({'csrf_token': 'foo'}) + request.headers = {'X-CSRF-Token': 'bar'} + view = self.config._derive_view(inner_view, require_csrf='DUMMY') + self.assertRaises(BadCSRFToken, lambda: view(None, request)) + def test_csrf_view_uses_config_setting_truthy(self): response = DummyResponse() def inner_view(request): diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py index 41102319d..e9ff09416 100644 --- a/pyramid/viewderivers.py +++ b/pyramid/viewderivers.py @@ -488,7 +488,9 @@ def csrf_view(view, info): wrapped_view = view if val: def csrf_view(context, request): - if request.method == 'POST': + # Assume that anything not defined as 'safe' by RFC2616 needs + # protection + if request.method not in {"GET", "HEAD", "OPTIONS", "TRACE"}: check_csrf_token(request, val, raises=True) return view(context, request) wrapped_view = csrf_view |
