diff options
| author | Paul Everitt <paul@agendaless.com> | 2013-07-07 08:47:56 -0400 |
|---|---|---|
| committer | Paul Everitt <paul@agendaless.com> | 2013-07-07 08:47:56 -0400 |
| commit | d44d0e044555cd1287680fc8368632a64ebe979b (patch) | |
| tree | 8a70d4025a8ee19b82e2a915bc668130b405cf93 /docs | |
| parent | 47eaa189e115936a86357380accd8d472e4d9a6c (diff) | |
| parent | d59440878b67b65e57c91c7b4aa8e7cbf943a729 (diff) | |
| download | pyramid-d44d0e044555cd1287680fc8368632a64ebe979b.tar.gz pyramid-d44d0e044555cd1287680fc8368632a64ebe979b.tar.bz2 pyramid-d44d0e044555cd1287680fc8368632a64ebe979b.zip | |
Merge branch 'master' of github.com:Pylons/pyramid
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/designdefense.rst | 2 | ||||
| -rw-r--r-- | docs/narr/resources.rst | 2 | ||||
| -rw-r--r-- | docs/narr/sessions.rst | 92 |
3 files changed, 73 insertions, 23 deletions
diff --git a/docs/designdefense.rst b/docs/designdefense.rst index fdc57e0c1..ea46053a0 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1691,7 +1691,7 @@ some sort of monolithic thing, and a lot of its software is usable externally. And while it's not really the job of this document to defend it, Zope has been around for over 10 years and has an incredibly large, active community. If you don't believe this, -http://taichino.appspot.com/pypi_ranking/authors is an eye-opening reality +http://pypi-ranking.info/author is an eye-opening reality check. Love Simplicity diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst index 699a3d4ac..b1bb611e5 100644 --- a/docs/narr/resources.rst +++ b/docs/narr/resources.rst @@ -300,7 +300,7 @@ the resource by :meth:`~pyramid.request.Request.resource_url`. The ``__resource_url__`` hook is passed two arguments: ``request`` and ``info``. ``request`` is the :term:`request` object passed to :meth:`~pyramid.request.Request.resource_url`. ``info`` is a dictionary with -two keys: +the following keys: ``physical_path`` A string representing the "physical path" computed for the resource, as diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index c4f4b5f07..7ec280c8a 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -298,14 +298,15 @@ Preventing Cross-Site Request Forgery Attacks `Cross-site request forgery <http://en.wikipedia.org/wiki/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 secretly 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 the correct *CSRF -token* has been set in an :app:`Pyramid` session object before performing any -actions in code which requires elevated privileges that is invoked via a form -post. To use CSRF token support, you must enable a :term:`session factory` +phenomenon whereby a user who is logged in to your website might inadvertantly +load a URL because it is linked from, or embedded in, an attacker's website. +If the URL is one that may modify or delete data, the consequences can be dire. + +You can avoid most of these attacks by issuing a unique token to the browser +and then requiring that it be present in all potentially unsafe requests. +:app:`Pyramid` sessions provide facilities to create and check CSRF tokens. + +To use CSRF tokens, you must first enable a :term:`session factory` as described in :ref:`using_the_default_session_factory` or :ref:`using_alternate_session_factories`. @@ -324,33 +325,82 @@ To get the current CSRF token from the session, use the The ``session.get_csrf_token()`` method accepts no arguments. It returns a CSRF *token* string. If ``session.get_csrf_token()`` or -``session.new_csrf_token()`` was invoked previously for this session, the +``session.new_csrf_token()`` was invoked previously for this session, then the existing token will be returned. If no CSRF token previously existed for -this session, a new token will be will be set into the session and returned. +this session, then a new token will be will be set into the session and returned. The newly created token will be opaque and randomized. You can 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.get_csrf_token()`` *again* to obtain the -current CSRF token related to the user from the session, and compare it to -the value of the hidden form field. For example, if your form rendering -included the CSRF token obtained via ``session.get_csrf_token()`` as a hidden -input field named ``csrf_token``: +posts to a method that requires elevated privileges, or supply it as a request +header in AJAX requests. + +For example, include the CSRF token as a hidden field: + +.. code-block:: html + + <form method="post" action="/myview"> + <input type="hidden" name="csrf_token" value="${request.session.get_csrf_token()}"> + <input type="submit" value="Delete Everything"> + </form> + +Or, include it as a header in a jQuery AJAX request: + +.. code-block:: javascript + + var csrfToken = ${request.session.get_csrf_token()}; + $.ajax({ + type: "POST", + url: "/myview", + headers: { 'X-CSRF-Token': csrfToken } + }).done(function() { + alert("Deleted"); + }); + + +The handler for the URL that receives the request +should then require that the correct CSRF token is supplied. + +Using the ``session.check_csrf_token`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In request handling code, you can check the presence and validity of a CSRF +token with ``session.check_csrf_token(request)``. If the token is valid, +it will return True, otherwise it will raise ``HTTPBadRequest``. + +By default, it checks for a GET or POST parameter named ``csrf_token`` or a +header named ``X-CSRF-Token``. .. code-block:: python - :linenos: - token = request.session.get_csrf_token() - if token != request.POST['csrf_token']: - raise ValueError('CSRF token did not match') + def myview(request): + session = request.session + + # Require CSRF Token + session.check_csrf_token(request): + + ... .. index:: single: session.new_csrf_token +Checking CSRF Tokens With A View Predicate +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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_route`. + +.. code-block:: python + + @view_config(request_method='POST', check_csrf=True, ...) + def myview(request): + ... + + Using the ``session.new_csrf_token`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To explicitly add a new CSRF token to the session, use the +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 |
