How to Use CSRF Protection in Flask: Simple Guide
To use
CSRF protection in Flask, install and configure the Flask-WTF extension which adds a secure token to your forms automatically. Enable it by setting a SECRET_KEY in your app and using FlaskForm for your forms to include CSRF tokens that protect against cross-site request forgery attacks.Syntax
To enable CSRF protection in Flask, you need to:
- Set a
SECRET_KEYin your Flask app for security. - Use the
Flask-WTFextension which providesCSRFProtectandFlaskForm. - Create forms by inheriting from
FlaskFormwhich automatically adds a hidden CSRF token field. - Use
csrf.init_app(app)to activate CSRF protection on your app.
python
from flask import Flask from flask_wtf import FlaskForm, CSRFProtect from wtforms import StringField, SubmitField app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' csrf = CSRFProtect() csrf.init_app(app) class MyForm(FlaskForm): name = StringField('Name') submit = SubmitField('Submit')
Example
This example shows a simple Flask app with CSRF protection enabled using Flask-WTF. The form includes a CSRF token automatically, and submitting the form validates the token to prevent CSRF attacks.
python
from flask import Flask, render_template_string, request from flask_wtf import FlaskForm, CSRFProtect from wtforms import StringField, SubmitField from wtforms.validators import DataRequired app = Flask(__name__) app.config['SECRET_KEY'] = 'a-very-secret-key' csrf = CSRFProtect() csrf.init_app(app) class NameForm(FlaskForm): name = StringField('Your Name', validators=[DataRequired()]) submit = SubmitField('Submit') @app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): return f"Hello, {form.name.data}!" return render_template_string(''' <form method="POST"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name() }}<br> {{ form.submit() }} </form> ''', form=form) if __name__ == '__main__': app.run(debug=True)
Output
Running the app and visiting '/' shows a form with a name input and submit button. Submitting the form with a name displays a greeting like "Hello, Alice!". If the CSRF token is missing or invalid, the form submission is rejected with a 400 error.
Common Pitfalls
- Not setting
SECRET_KEYcauses CSRF protection to fail silently or raise errors. - Forgetting to use
FlaskFormorform.hidden_tag()in templates means the CSRF token is not included. - Disabling CSRF protection on POST routes by mistake leaves your app vulnerable.
- Using AJAX or API calls without sending the CSRF token causes validation failures.
python
from flask import Flask, render_template_string from flask_wtf import FlaskForm, CSRFProtect from wtforms import SubmitField app = Flask(__name__) app.config['SECRET_KEY'] = 'secret' csrf = CSRFProtect() csrf.init_app(app) class BadForm(FlaskForm): submit = SubmitField('Submit') @app.route('/', methods=['GET', 'POST']) def bad(): form = BadForm() if form.validate_on_submit(): return 'Success' return render_template_string(''' <form method="POST"> <!-- Missing form.hidden_tag() --> {{ form.submit() }} </form> ''', form=form) # Correct way includes form.hidden_tag() to add CSRF token @app.route('/good', methods=['GET', 'POST']) def good(): form = BadForm() if form.validate_on_submit(): return 'Success' return render_template_string(''' <form method="POST"> {{ form.hidden_tag() }} {{ form.submit() }} </form> ''', form=form)
Quick Reference
- Always set
app.config['SECRET_KEY']before enabling CSRF. - Use
FlaskFormfor your forms to get CSRF tokens automatically. - Include
{{ form.hidden_tag() }}in your form templates to insert the CSRF token field. - Enable CSRF protection with
CSRFProtect(app). - For AJAX requests, send the CSRF token in headers or data.
Key Takeaways
Set a strong SECRET_KEY in your Flask app to enable CSRF protection.
Use Flask-WTF's FlaskForm to automatically add CSRF tokens to your forms.
Always include form.hidden_tag() in your HTML forms to insert the CSRF token field.
Enable CSRFProtect on your app to activate CSRF validation on POST requests.
Remember to send CSRF tokens with AJAX requests to avoid validation errors.