pythonflaskflask-wtformscsrf-protection

How to use Flask-WTForms CSRF protection with AJAX?


Flask-WTForms provides CSRF protection. It works great when using normal HTML forms, but the process is less clear when using AJAX. I have a file upload in my form, and I split the process in two with AJAX: the file goes to the upload endpoint while the rest of the form goes to the submit endpoint. Since the file is posted with AJAX, it doesn't get a CSRF token, but I want to protect the upload endpoint from attacks. How can I generate a CSRF token when using AJAX?

@app.route('/submit', methods=["GET","POST"])
@login_required
def submit():
    form = MyForm()

    if request.method == "POST" and form.validate():
        # success, csrf checks out and data is validated
        # do stuff

    csrf_for_uploads = # generate csrf?
    return render_template('some_form.html', form=form, csrf_for_uploads=csrf_for_uploads)

@app.route('/upload', methods=["POST"])
@login_required
def upload():
    myfile = request.files['file']
    # How do I verify CSRF now?

Solution

  • The documentation speaks a bit about implementing CSRF protection with regards to AJAX.

    You can enable the module:

    from flask_wtf.csrf import CsrfProtect
    
    CsrfProtect(app)
    

    and then use this in your AJAX POST call:

    <meta name="csrf-token" content="{{ csrf_token() }}">
    
    var csrftoken = $('meta[name=csrf-token]').attr('content')
    
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken)
            }
        }
    })
    

    Hope this helps!