Skip to content

Commit

Permalink
Have Automatic CSRF on all unsafe HTTP methods
Browse files Browse the repository at this point in the history
Instead of only protecting against unsafe POST requests, have the automatic
CSRF protect on all methods which are not defined as "safe" by RFC2616.
  • Loading branch information
dstufft committed Apr 15, 2016
1 parent 699c647 commit 9028dd1
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 11 deletions.
9 changes: 5 additions & 4 deletions docs/narr/sessions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions docs/narr/viewconfig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
4 changes: 2 additions & 2 deletions docs/whatsnew-1.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions pyramid/tests/test_viewderivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,17 @@ def inner_view(request): pass
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):
Expand Down
4 changes: 3 additions & 1 deletion pyramid/viewderivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9028dd1

Please sign in to comment.