5.8. Flask-WTF#

To help us prevent CSRF in our flask apps we can use the flask-wtf library. This library makes using the WTForms rendering and validation library easier in flask apps.

flask-wtf allows us to:

  • specify forms in Python

  • render these forms into our templates as HTML

  • include CSRF tokens

  • validate form data and CSRF tokens

5.8.1. Configuration#

To enable CSRF protection you need to wrap the app with CSRFProtect, which automatically checks the CSRF on form data posted to each route.

from flask_wtf.csrf import CSRFProtect

CSRFProtect(app)

5.8.2. Defining Forms#

The example below creates a form for submitting comments to FakeTube.

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired


class CommentForm(FlaskForm):
    comment = StringField(
        "comment",
        validators=[DataRequired()],
        render_kw={"placeholder": "Add a public comment..."},
    )

5.8.3. Rendering Forms into Templates#

To render the form into a template we can pass a form instance to the render_template function e.g.

form = CommentForm()
return render_template("index.html", form=form)

Then inside our index.html template we can include the CSRF and form contents

<form method="POST" action="/comment">
    {{ form.hidden_tag() }}  <!-- Automatically includes CSRF token -->
    {{ form.comment }}  <!-- Render the comment field -->
    <p><input type="submit" value="Post Comment"></p>
</form>

5.8.4. Validating Forms#

In the route that handles the POST -ed form data we simply need to create an instance of the form. flask-wtf will handle converting the POST data into a form for us.

From the documentation :

Note that you don’t have to pass request.form to Flask-WTF; it will load automatically. And the convenient validate_on_submit will check if it is a POST request and if it is valid.

Example:

form = CommentForm()
if form.validate_on_submit():
    flash(f"Comment posted: {form.comment.data}", "success")
    return redirect("/")
Demo: Fix the CSRF

In this demo, we’ve fixed the CSRF vulnerability on FakeTube by using flask-wtf to:

  • create and render a form in the template

  • embed a CSRF token

  • validate the CSRF token and form input on submission

If the CSRF token is invalid, then an error will be returned by the flask app.

Instructions

TUTORIAL_fix_the_csrf.zip

  1. Run the FakeTube app

python app.py

Then open the site in your browser.

  1. Run the scam comment app (at the same time)

python scam_app.py

Then open the site in your browser.

  1. Click to claim your free iPhones

  2. Error! The cross-site request has been blocked.

../../_images/csrf_fixed_no_ed_loop.gif