I was looking at the ``csrfmiddleware`` package by Luke Plant and
David Turner for a middleware solution the implements CRSF-protection
across my site.

Some short-comings of this middleware for a who-app:

- Relies on beaker to provide undiscoverable authorization; we already
have the who cookie value which has same semantics.
- Does not provide functionality to authorize Ajax-requests.

Based on the attached doc, I'm going to implement a repoze.who-based
middleware which overcomes the above. Additionally, I'm going to use
``repoze.xmliter`` to allow multiple middlewares to process XML
without reparsing.

Feedback welcome.


This package provides a WSGI middleware which relies on ``repoze.who``
cookie authentiation to implement CSRF form protection [1].


In order to ensure that POST requests (which may be assumed to have
side-effects) stem from authorized forms, requests must include a
parameter that can only be known in theory by the authenticated user
and the website.

One such parameter is the ``repoze.who`` authentication cookie value,
which is a digest based on the authentication credentials.

The middleware creates a token based on a configurable seed and the
cookie value. Only requests that can produce this token are allowed
(the "403 Forbidden" status is returned otherwise).

It's imperative that the token is not discoverable by third party.

Extracting the validation token

Before looking at the POST data, the middleware consults the
"X-Form-Protect" request header.

If not found, the POST data is examined for a "__protect" key.

Form authentication

The middleware intercepts HTML content and adds CSRF form
authentication to all forms appearing on the page (by adding a hidden
input field with the name "__protect").

Once verified, the parameter is stripped from the request before it
reaches the WSGI application.

Identity metadata

A ``repoze.who`` metadata provider is available and adds a
"form_protection_token" entry to the identity object.

A utility-method is available to retrieve the token from the identity.

  >>> from repoze.formprotect import get_form_protection_token
  >>> token = get_form_protection_token(identity)

Note that this metadata is only required if form protection needs to
be handled manually.
Ajax support

Using a JavaScript library such as jQuery, it's possible to submit
Ajax-requests that use the POST request method, without the use of a
In order to authenticate such requests, either a valid form protection
parameter or request header must be submitted (see above).

To enable for all ajax-requests, bind an event listener for the jQuery
"ajaxSend" event, which adds the form validation request header [2].

  jQuery.bind("ajaxSend", function(event, request, settings) {
     request.setRequestHeader("X-Form-Protect", %token)


[1] http://en.wikipedia.org/wiki/Cross-site_request_forgery
[2] http://www.w3.org/TR/XMLHttpRequest/#xmlhttprequest


Malthe Borch <mbo...@gmail.com>
Repoze-dev mailing list

Reply via email to