Joseph
Joseph

Reputation: 145

tornado.web.stream_request_body: _xsrf missing error even with _xsrf input within html

Utilizing the Tornado library within Python I have come across a very unusual error. It seems that when I have decorated my file upload handler with '@tornado.web.stream_request_body' the webserver throws the error:

WARNING:tornado.general:403 POST /upload (ip-address): '_xsrf' argument missing from POST
WARNING:tornado.access:403 POST /upload (ip-address) 1.44ms

The code governing the upload is as follows:

@tornado.web.stream_request_body
class Upload(BaseHandler):
    def prepare(self):
        print self.request.headers

    def data_received(self,chunk):
        print chunk

    @tornado.web.authenticated
    def post(self):
        self.redirect("/")

where my BaseHandler is a web.RequestHandler subclass with various helper functions (retrieving user info from cookies and whatnot).

Within my HTML template, I have the appropriate xsrf function call as seen here:

<form enctype="multipart/form-data" action="/upload" method="post" id="upload_form" class="form-upload">
    {% raw xsrf_form_html() %}
    <input type="file" name="upFile" required/>
    <button class="btn btn-lg btn-primary btn-block-submit" type="submit">Submit</button>
</form>

and is generating the proper xsrf input within the browser:

<form enctype="multipart/form-data" action="/upload" method="post" id="upload_form" class="form-upload">
    <input type="hidden" name="_xsrf" value="2|787b7c6e|4a82eabcd1c253fcabc9cac1e374e913|1430160367"/>
    <input type="file" name="upFile" required/>
    <button class="btn btn-lg btn-primary btn-block-submit" type="submit">Submit</button>
</form>

When I turn off xsrf_cookies within the webserver settings, all is well and everything functions as normal. However I feel that this is not ideal.

While xsrf_cookies is set to False, if given a text file called "stuff.txt" with a body of "testfile" the output is:

------WebKitFormBoundary4iHkIqUNgfqVErRB
Content-Disposition: form-data; name="_xsrf"

2|787b7c6e|4a82eabcd1c253fcabc9cac1e374e913|1430160367
------WebKitFormBoundary4iHkIqUNgfqVErRB
Content-Disposition: form-data; name="upFile"; filename="stuff.txt"
Content-Type: text/plain

testfile
------WebKitFormBoundary4iHkIqUNgfqVErRB--

From that output, my guess is that the xsrf value is being captured by the stream_request_body and not passed to the appropriate xsrf validation class.

Any help on this would be greatly appreciated. Thank you in advance!

Upvotes: 0

Views: 747

Answers (1)

Ben Darnell
Ben Darnell

Reputation: 22134

Tornado does not currently (as of version 4.1) support streaming multi-part uploads. This means that uploads you wish to stream must be simple PUTs, instead of a POST that mixes the uploaded data with other form fields like _xsrf. To use XSRF protection in this scenario you must pass the XSRF token via an HTTP header (X-Xsrf-Token) instead of via a form field. Unfortunately this is incompatible with non-javascript web form uploads; you must have a client capable of setting arbitrary HTTP headers.

Upvotes: 3

Related Questions