CSRF Protection in Flask
Cross-Site Request Forgery (CSRF) is a security vulnerability where an attacker tricks a user into unknowingly submitting a request to a web application in which they are authenticated. This can lead to unauthorized actions being performed on behalf of the user, such as changing account settings or making transactions.
How to Prevent CSRF Attacks?
One of the most effective ways to prevent CSRF attacks is by using CSRF tokens. These tokens are unique, dynamically generated values included in forms and verified by the server when a request is made. Since attackers cannot predict these tokens, they are unable to forge valid requests.
.png)
Implementing CSRF Protection in Flask
Step 1: Install Dependencies
To implement CSRF protection in Flask, install the required packages using:
pip install flask flask-wtf
Step 2: Set Up Flask Application
In Flask, CSRF protection can be enabled using Flask-WTF, which provides automatic CSRF protection for forms. Below is a basic example:
from flask import Flask, render_template, request, flash
from flask_wtf import FlaskForm, CSRFProtect
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.secret_key = 'your_secret_key' # Required for CSRF protection
csrf = CSRFProtect(app) # Enable CSRF Protection
# Creating a FlaskForm to manage CSRF properly
class NameForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
submit = SubmitField('Submit')
@app.route("/", methods=['GET', 'POST'])
def index():
form = NameForm()
if request.method == 'POST':
if form.validate_on_submit():
name = form.name.data
flash(f'Hello {name} from Protected Form!', 'success')
return render_template('index.html', form=form)
else:
flash('CSRF Token Missing or Invalid!', 'danger')
return render_template('index.html', form=form)
@app.route("/unprotected_form", methods=['POST'])
def unprotected_form():
name = request.form.get('Name', '').strip()
if not name:
return "Error: Name is required!", 400
return f'Hello {name} from Unprotected Form!'
if __name__ == '__main__':
app.run(debug=True)
Step 3: Create a Secure HTML Form
A simple HTML page with CSRF-protected and unprotected forms:
<!DOCTYPE html>
<html>
<head>
<title>CSRF Protection Demo</title>
</head>
<body>
<h2>Protected Form (CSRF Token Required)</h2>
<form action="{{ url_for('index') }}" method="POST">
{{ form.hidden_tag() }} <!-- This automatically includes CSRF token -->
<label for="Name">Your Name Please?</label>
{{ form.name() }} <!-- Flask-WTF handles input -->
{{ form.submit() }} <!-- Submit button -->
</form>
<h2>Unprotected Form (No CSRF Token)</h2>
<form action="{{ url_for('unprotected_form') }}" method="POST">
<label for="Name">Your Name Please?</label>
<input type="text" name="Name" required>
<button type="submit">Submit</button>
</form>
<!-- Flash Messages -->
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
<p style="color: {{ 'red' if category == 'danger' else 'green' }}">{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
</body>
</html>
Step 4: Run the Flask Application
Run the app in development mode using command-
python app.py
Step 5: Testing the CSRF Protection
- Open http://127.0.0.1:5000/protected_form in your browser.
- Try submitting both forms:
- Unprotected Form: Submits without any token, making it vulnerable to CSRF attacks.
- Protected Form: Requires a valid CSRF token to submit successfully.
- If you try submitting the protected form without the CSRF token, an error will occur, preventing unauthorized requests.




Note: To submit forms that require CSRF tokens, use hidden_tag() method of Flask-WTF, it automatically generates hidden fields including CSRD token inside a form.