RandallShanePhD
RandallShanePhD

Reputation: 5804

Escaping xsrf in Tornado with javascript POST

I have a simple form I would like to submit to a Tornado POST and I am running xsrf in tornado. The following produces the known error: '_xsrf' argument missing from POST

Has anyone solved how to submit the xsrf (like {% module xsrf_form_html() %}) in a regular HTML form using javascript? Here is the code:

<form action="#" id="form_field">
    {% raw xsrf_form_html() %}  # DOES NOT WORK!
   <p><input type="text" id="field1" value=""></p>
</form>

<button id="button">UPDATE</button>

<script>
  button.onclick = function changeField() {
    var xhr = new XMLHttpRequest();
        xhr.open("POST", "/chatdata", true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(JSON.stringify({
            value: document.getElementById("field1").value
        }))
    };
</script>

Upvotes: 0

Views: 767

Answers (2)

Ben Darnell
Ben Darnell

Reputation: 22154

xsrf_form_html is for traditional html forms using x-www-form-urlencoded. It won't be recognized if you submit your form as JSON. To use non-form-based encodings with Tornado's XSRF protection, pass the XSRF token as a X-XSRF-Token X-XSRFToken HTTP header.

Upvotes: 1

Patrick Evans
Patrick Evans

Reputation: 42746

According to the documentation page you would just create a request that has a _xsrf request field, for example a x-www-urlencoded string of _xsrf=yourtoken. The way you had it you were sending just some JSON that had a value property, ie {"value":"token"}.

Now you can get the token in a couple ways from what I have seen, either through a set cookie or from the field that is generated from the xsrf_form_html() call.

From cookie

//helper function to read cookie, from http://www.tornadoweb.org/en/stable/guide/security.html sample
function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}

var data = "_xsrf="+getCookie('_xsrf');
//note using this method you don't set the content-type, 
//you want it to default to x-www-urlencoded
xhr.send(data);

Note you would have to build up the string to contain your other input form fields, either directly or through library methods like jQuery's serialize()

If want to just use the data straight from the form without the hassle of grabbing each input and generating a proper x-www-urlencoded string yourself; Then continue using xsrf_form_html() and create a FormData object from that form and send that. When you pass a form element to FormData() it will collect all the input values for you.

var data = new FormData( document.getElementById('form_field') );
//again no need to set the content-type as it will be automatically set internally
xhr.send(data);
//You could also use library methods like jQuery's serialize()
var data = jQuery('#form_field').serialize();
xhr.send(data);

Using FormData helps if you don't know how to get a reference to the generated field directly. Though it would more than likely have name="_xsrf" so a selector like input[name="_xsrf"] should find it. Though you would have to look at the generated html to find out.

var data = "_xsrf="+document.querySelector('input[name="_xsrf"]').value

Upvotes: 0

Related Questions