Search code examples
postbackbone.jscookiestornadocsrf

Tornado XSRF token without templating


I am currently implementing a project containing Backbone Marionette over Tornado and am running into an issue with the XSRF token. Since the XSRF is not delivered through a template (by means of xsrf_form_html() ), when a user logs in the app makes a GET request to the login url "//login" and retrieves the xsrf token by means of:

class LoginHandler(BaseHandler):
"""
"""

def get(self):
    token = self.xsrf_token
    self.respond(dict(_xsrf=token))

self.respond looks like:

def respond(self, response=None):
    """
    :param data:
    :return:
    """

    if response is not None:
        self.set_header('Content-Type', 'application/json')
        self.write(json.dumps(response))
    else:
        self.set_header('Content-Type', 'text/plain')
        self.write("")

However, whenever a POST (with a field value of "_xsrf" : token ) is made to the server, I get the iconic " XSRF cookie does not match POST argument". It looks as if the xsrf token on the server is being re-generated at every request since the xsrf cookie does not exist (so far my attempts to ensure that the cookie exists has failed...not entirely sure how to persist that). Perhaps I'm missing (or misunderstanding) something critical here, but I was hoping someone else out there had encountered a paradigm like this and has a solution or suggestion.

Thanks in advance!


Solution

  • The xsrf token has to be sent in two different ways and they have to match. Once in the cookie, and once either in a header or in a form-encoded POST body (the body cannot be json and must have a form-encoded or multipart content-type). Headers are generally preferred as long as your clients can send them; you need to send both Cookie: _xsrf=foo and X-Xsrf-Token: foo.

    Since Tornado 3.2.2, xsrf tokens include a random component to counter the BREACH attack, so two tokens can match without being identical.