From 6b35eb6ca3b271e2943d37307c925c5733e082d9 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 10 Apr 2016 20:50:10 -0500 Subject: rewrite csrf checks to support a global setting to turn it on - only check csrf on POST - support "pyramid.require_default_csrf" setting - support "require_csrf=True" to fallback to the global setting to determine the token name --- docs/narr/sessions.rst | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'docs/narr/sessions.rst') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index db554a93b..3baed1cb8 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -389,8 +389,43 @@ header named ``X-CSRF-Token``. # ... -.. index:: - single: session.new_csrf_token +.. _auto_csrf_checking: + +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. + +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. + +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 +same format as the ``pyramid.require_default_csrf`` setting, accepting strings +or boolean values. + +If ``require_csrf`` is ``True`` but does not explicitly define a token to +check, then the token name is pulled from whatever was set in the +``pyramid.require_default_csrf`` setting. Finally, if that setting does not +explicitly define a token, then ``csrf_token`` is the token required. This token +name will be required in ``request.params`` which is a combination of the +query string and a submitted form body. + +It is always possible to pass the token in the ``X-CSRF-Token`` header as well. +There is currently no way to define an alternate name for this header without +performing CSRF checking manually. + +If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` exception +will be raised. This exception may be caught and handled by an +:term:`exception view` but, by default, will result in a ``400 Bad Request`` +resposne being sent to the client. Checking CSRF Tokens with a View Predicate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -411,6 +446,9 @@ include ``check_csrf=True`` as a view predicate. See instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different from calling :func:`pyramid.session.check_csrf_token`. +.. index:: + single: session.new_csrf_token + Using the ``session.new_csrf_token`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 15b97dc81c8bcdc039f8f2293f85812f68a076da Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 10 Apr 2016 20:51:23 -0500 Subject: deprecate the check_csrf predicate --- docs/narr/sessions.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs/narr/sessions.rst') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 3baed1cb8..4e8f6db88 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -430,6 +430,10 @@ resposne being sent to the client. Checking CSRF Tokens with a View Predicate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. deprecated:: 1.7 + Use the ``require_csrf`` option or read :ref:`auto_csrf_checking` instead + to have :class:`pyramid.exceptions.BadCSRFToken` exceptions raised. + A convenient way to require a valid CSRF token for a particular view is to include ``check_csrf=True`` as a view predicate. See :meth:`pyramid.config.Configurator.add_view`. -- cgit v1.2.3 From 769da1215a0287f4161e58f36d8d4b7650154202 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 10 Apr 2016 21:14:22 -0500 Subject: cleanup some references in the docs --- docs/narr/sessions.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'docs/narr/sessions.rst') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 4e8f6db88..d66e86258 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -367,6 +367,21 @@ Or include it as a header in a jQuery AJAX request: The handler for the URL that receives the request should then require that the correct CSRF token is supplied. +.. index:: + single: session.new_csrf_token + +Using the ``session.new_csrf_token`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To explicitly create a new CSRF token, use the ``session.new_csrf_token()`` +method. This differs only from ``session.get_csrf_token()`` inasmuch as it +clears any existing CSRF token, creates a new CSRF token, sets the token into +the session, and returns the token. + +.. code-block:: python + + token = request.session.new_csrf_token() + Checking CSRF Tokens Manually ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -425,7 +440,7 @@ performing CSRF checking manually. If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` exception will be raised. This exception may be caught and handled by an :term:`exception view` but, by default, will result in a ``400 Bad Request`` -resposne being sent to the client. +response being sent to the client. Checking CSRF Tokens with a View Predicate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -449,18 +464,3 @@ include ``check_csrf=True`` as a view predicate. See predicate system, when it doesn't find a view, raises ``HTTPNotFound`` instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different from calling :func:`pyramid.session.check_csrf_token`. - -.. index:: - single: session.new_csrf_token - -Using the ``session.new_csrf_token`` Method -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To explicitly create a new CSRF token, use the ``session.new_csrf_token()`` -method. This differs only from ``session.get_csrf_token()`` inasmuch as it -clears any existing CSRF token, creates a new CSRF token, sets the token into -the session, and returns the token. - -.. code-block:: python - - token = request.session.new_csrf_token() -- cgit v1.2.3 From f12005b92fa9bb33f082bd50747eb11791605cff Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Fri, 15 Apr 2016 17:41:35 -0400 Subject: Only Accept CSRF Tokens in headers or POST bodies Previously `check_csrf_token` would allow passing in a CSRF token in through a the URL of a request. However this is a security issue because a CSRF token must not be allowed to leak, and URLs regularly get copy/pasted or otherwise end up leaking to the outside world. --- docs/narr/sessions.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'docs/narr/sessions.rst') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index d66e86258..ad086268b 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -391,8 +391,8 @@ will return ``True``, otherwise it will raise ``HTTPBadRequest``. Optionally, you can specify ``raises=False`` to have the check return ``False`` instead of raising an exception. -By default, it checks for a GET or POST parameter named ``csrf_token`` or a -header named ``X-CSRF-Token``. +By default, it checks for a POST parameter named ``csrf_token`` or a header +named ``X-CSRF-Token``. .. code-block:: python @@ -430,8 +430,7 @@ If ``require_csrf`` is ``True`` but does not explicitly define a token to check, then the token name is pulled from whatever was set in the ``pyramid.require_default_csrf`` setting. Finally, if that setting does not explicitly define a token, then ``csrf_token`` is the token required. This token -name will be required in ``request.params`` which is a combination of the -query string and a submitted form body. +name will be required in ``request.POST`` which is the submitted form body. It is always possible to pass the token in the ``X-CSRF-Token`` header as well. There is currently no way to define an alternate name for this header without -- cgit v1.2.3 From 21d5beaed1641e1f50ab1ab3c481b1c8f3ad1173 Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Fri, 15 Apr 2016 17:59:55 -0400 Subject: Have Automatic CSRF on all unsafe HTTP methods Instead of only protecting against unsafe POST requests, have the automatic CSRF protect on all methods which are not defined as "safe" by RFC2616. --- docs/narr/sessions.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'docs/narr/sessions.rst') 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 -- cgit v1.2.3 From 65dee6e4ca0c0c607e97db0c9e55768f10591a58 Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Fri, 15 Apr 2016 20:42:20 -0400 Subject: In addition to CSRF token, verify the origin too Add an additional layer of protection against CSRF by verifying the actual origin of the request in addition to the CSRF token. We only do this check on sites hosted behind HTTPS because only HTTPS sites have evidence to show that the Referrer header is not being spuriously removed by random middleware boxes. --- docs/narr/sessions.rst | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'docs/narr/sessions.rst') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 0e895ff81..7cf96ac7d 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -437,6 +437,14 @@ It is always possible to pass the token in the ``X-CSRF-Token`` header as well. There is currently no way to define an alternate name for this header without performing CSRF checking manually. +In addition to token based CSRF checks, the automatic CSRF checking will also +check the referrer of the request to ensure that it matches one of the trusted +origins. By default the only trusted origin is the current host, however +additional origins may be configured by setting +``pyramid.csrf_trusted_origins`` to a list of domain names (and ports if they +are non standard). If a host in the list of domains starts with a ``.`` then +that will allow all subdomains as well as the domain without the ``.``. + If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` exception will be raised. This exception may be caught and handled by an :term:`exception view` but, by default, will result in a ``400 Bad Request`` -- cgit v1.2.3