Flask-wtf: csrf_token is removed from session befo

2019-05-11 08:11发布

I'm using Flask with Flask-Security (specifically Flask-WTF regarding my csrf issue) to "ease" the process of register/loggin users (not easy so far). I'm using BackboneJS on the front-end, therefore I kind of hacked the original way to use Flask-WTF. Indeed, I make an AJAX GET request on /register to get the register page (generated by Flask-Security) and I put the resulting HTML in a modal.

render: function () {
            var self = this;
            $.ajax({
                type: 'GET',
                url: Config.constants.serverGateway + "/register"
            }).done(function(result){
                console.log("get register done", result);
                var html = self.template({ config: Config, form: result });
                self.$el.html(html);
            }).fail(function(error){
                console.log("Could not get register token", error);
                var html = this.errorTemplate({ config: Config });
                self.$el.html(html);
            });

            return this;
        }

This way I have the generated csrf, and when I POST the registration data, I send the right csrf along the user data (email and password).

submit: function () {
            console.log("submit");
            var self = this;
            var formData = this.$el.find('form').serialize();
            $.ajax({
                type: 'POST',
                url: Config.constants.serverGateway + "/register",
                data: formData,
                dataType: 'json'
            }).done(function(result){
                self.trigger('close');
            }).fail(function(error){
                console.log("Could not submit register data", error);
            });
        }

On the server-side, I can debug my python code to see that the csrf_token which has been generated when I requested the register page has disappeared from the session object, therefore leading to the generation of a new one, which of course didn't match the one I send with my form. The session is still the same though, as the _id is the same during the GET and the POST.

You can see the code in flask_wtf/csrf.py::generate_csrf(), which is called when creating the form object in the ::register function from flask_security/views.py

if 'csrf_token' not in session:
    session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()

It results in a CSRF TOKEN MISSING error.

An additionnal information, is that my front-end and back-end are delivered by the same server, as they have a different port number.

Last, when I use an href on front-end and display the page returned by the server on the 'GET' request, submitting the form works well. I just liked to display this registration form in a modal.

Thanks for your help

2条回答
女痞
2楼-- · 2019-05-11 08:53

(I'm answering here since I can't comment) @junnytony Yes I have the token in my modal and I send it in my POSt request. When I debug the Flask application, I can see the toekn I sent with my POST request, the problem is that it should be compared to the one in the session to be validated, but the one in the session has disappearred, so the flask-wtf lib generates a new one, which results in a failure when comparing with the one I sent.

查看更多
\"骚年 ilove
3楼-- · 2019-05-11 08:59

Okay, I finally figured out the solution to my problem. I feel like a noob (which I am).

The problem lied in the session credentials which were not sent to the server with the requests, so that the server coudldn't access the session cookie. I found the solution in the following tutorial: http://backbonetutorials.com/cross-domain-sessions/ To send it, i added the following lines in my Backbone router initialize function:

// Use withCredentials to send the server cookies
// The server must allow this through response headers
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
    options.xhrFields = {
        withCredentials: true
    };
});

This makes all AJAX requests include the withCredentials = true. On the server-side, I had to set Access-Control-Allow-Credentials:true. Since I'm using flask-cors, it is done with [supports_credentials=True][2] when creating the CORS object.

查看更多
登录 后发表回答