From 319793d9b3d127ba2a9245713ef4f01b32918e95 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Dec 2010 18:27:07 -0500 Subject: - Added CSRF token generation, as described in the narrative chapter entitled "Preventing Cross-Site Request Forgery Attacks". --- docs/narr/csrf.rst | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 docs/narr/csrf.rst (limited to 'docs/narr/csrf.rst') diff --git a/docs/narr/csrf.rst b/docs/narr/csrf.rst new file mode 100644 index 000000000..7d1ee6fea --- /dev/null +++ b/docs/narr/csrf.rst @@ -0,0 +1,63 @@ +.. _csrf_chapter: + +Preventing Cross-Site Request Forgery Attacks +============================================= + +`Cross-site request forgery +`_ attacks are a +phenomenon whereby a user with an identity on your website might click on a +URL or button on another website which unwittingly redirects the user to your +application to perform some command that requires elevated privileges. + +You can avoid most of these attacks by making sure that a the correct *CSRF +token* has been set in an :app:`Pyramid` session object before performing any +actions in code which requires elevated privileges and is invoked via a form +post. To use CSRF token support, you must enable a :term:`session factory` +as described in :ref:`using_the_default_session_factory` or +:ref:`using_alternate_session_factories`. + +Using the ``session.new_csrf_token`` Method +------------------------------------------- + +To add a CSRF token to the session, use the ``session.new_csrf_token`` method. + +.. code-block:: python + :linenos: + + token = request.session.new_csrf_token() + +The ``.new_csrf_token`` method accepts no arguments. It returns a *token* +string, which will be opaque and randomized. This token will also be set +into the session, awaiting pickup by the ``session.pop_csrf_token`` method. +You can subsequently use the returned token as the value of a hidden field in +a form that posts to a method that requires elevated privileges. The handler +for the form post should use ``session.pop_csrf_token`` (explained below) to +pop the current CSRF token related to the user from the session, and compare +it to the value of the hidden form field. + +Using the ``session.pop_csrf_token`` Method +------------------------------------------- + +To pop the current CSRF token from the session, use the +``session.pop_csrf_token`` method. + +.. code-block:: python + :linenos: + + token = request.session.pop_csrf_token() + +The ``.pop_csrf_token`` method accepts no arguments. It returns the +"current" *token* string (as per the last call to +``session.new_csrf_token``). You can then use it to compare against the +token provided within form post hidden value data. For example, if your form +rendering included the CSRF token obtained via ``session.new_csrf_token`` as +a hidden input field named ``csrf_token``: + +.. code-block:: python + :linenos: + + token = request.session.pop_csrf_token() + if token != request.POST['csrf_token']: + raise ValueError('CSRF token did not match') + + -- cgit v1.2.3 From 36ea5b34b4ba25666a5b1d5fa86295e26395e921 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Dec 2010 22:59:54 -0500 Subject: Changed my mind. Never pop the CSRF token. Leave it around until a new one replaces it. --- docs/narr/csrf.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'docs/narr/csrf.rst') diff --git a/docs/narr/csrf.rst b/docs/narr/csrf.rst index 7d1ee6fea..7586b0ed7 100644 --- a/docs/narr/csrf.rst +++ b/docs/narr/csrf.rst @@ -28,35 +28,35 @@ To add a CSRF token to the session, use the ``session.new_csrf_token`` method. The ``.new_csrf_token`` method accepts no arguments. It returns a *token* string, which will be opaque and randomized. This token will also be set -into the session, awaiting pickup by the ``session.pop_csrf_token`` method. +into the session, awaiting pickup by the ``session.get_csrf_token`` method. You can subsequently use the returned token as the value of a hidden field in a form that posts to a method that requires elevated privileges. The handler -for the form post should use ``session.pop_csrf_token`` (explained below) to -pop the current CSRF token related to the user from the session, and compare -it to the value of the hidden form field. +for the form post should use ``session.get_csrf_token`` (explained below) to +obtain the current CSRF token related to the user from the session, and +compare it to the value of the hidden form field. -Using the ``session.pop_csrf_token`` Method +Using the ``session.get_csrf_token`` Method ------------------------------------------- -To pop the current CSRF token from the session, use the -``session.pop_csrf_token`` method. +To get the current CSRF token from the session, use the +``session.get_csrf_token`` method. .. code-block:: python :linenos: - token = request.session.pop_csrf_token() + token = request.session.get_csrf_token() -The ``.pop_csrf_token`` method accepts no arguments. It returns the -"current" *token* string (as per the last call to -``session.new_csrf_token``). You can then use it to compare against the -token provided within form post hidden value data. For example, if your form -rendering included the CSRF token obtained via ``session.new_csrf_token`` as -a hidden input field named ``csrf_token``: +The ``get_csrf_token`` method accepts no arguments. It returns the "current" +*token* string (as per the last call to ``session.new_csrf_token``). You can +then use it to compare against the token provided within form post hidden +value data. For example, if your form rendering included the CSRF token +obtained via ``session.new_csrf_token`` as a hidden input field named +``csrf_token``: .. code-block:: python :linenos: - token = request.session.pop_csrf_token() + token = request.session.get_csrf_token() if token != request.POST['csrf_token']: raise ValueError('CSRF token did not match') -- cgit v1.2.3