Welcome to our comprehensive guide on CSRF Protection in Flask! Let's dive right in! 💡
CSRF (Cross-Site Request Forgery) is an attack that tricks the user into submitting requests to a web application without their knowledge or consent. This lesson will teach you how to protect your Flask applications against CSRF attacks using Flask-WTF and Flask-CsrfProtect.
CSRF attacks can lead to unauthorized data modification, account takeover, and sensitive information disclosure. By implementing CSRF protection, you can significantly enhance the security of your Flask applications.
Before we begin, ensure you have the following prerequisites installed:
You can install them using pip:
pip install Flask Flask-WTF Flask-CsrfProtectLet's create a simple Flask application and integrate CSRF protection.
from flask import Flask, render_template, request, url_for, flash, redirect
from flask_wtf import CSRFProtect
from flask_wtf.html5_writer import SafeData
from wtforms import Form, StringField, SubmitField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
csrf = CSRFProtect(app)
class LoginForm(Form):
username = StringField('Username', validators=[ ])
password = StringField('Password', validators=[ ])
submit = SubmitField('Login')
@app.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm(request.form)
if request.method == 'POST' and form.validate():
if form.username.data == 'admin' and form.password.data == 'password':
return 'Login successful!'
else:
flash('Invalid username or password')
return redirect(url_for('index'))
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)In the above code, we've created a basic Flask application with a login form. Now, let's protect this form against CSRF attacks.
To integrate CSRF protection, we'll use Flask-WTF and Flask-CsrfProtect. First, we'll modify our form and templates to include CSRF tokens.
from flask_wtf.csrf import CSRFToken, CSRFError
@app.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm(request.form)
if request.method == 'POST' and not CSRFError.is_csrf_error(request, form):
if form.validate():
if form.username.data == 'admin' and form.password.data == 'password':
return 'Login successful!'
else:
flash('Invalid username or password')
return redirect(url_for('index'))
else:
return render_template('index.html', form=form, _csrf_token=form._csrf_token)
return render_template('index.html', form=form)
@app.context_processor
def inject_csrf():
return dict(csrf_token=CSRFToken())In the modified code, we've added the inject_csrf context processor, which adds the CSRF token to the template context. We also modified the index route to pass the CSRF token to the template and check for CSRF errors.
Next, let's modify the index.html template to include the CSRF token in the login form.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
</head>
<body>
<!-- ... -->
<form method="POST">
{% with csrf_token=csrf_token %}
{{ form.hidden_tag() }}
{{ form.username.label }}
{{ form.username }}
{{ form.password.label }}
{{ form.password }}
{{ form.submit }}
{% endwith %}
</form>
</body>
</html>In the modified template, we've wrapped the form with a with-block and added the hidden CSRF token field using form.hidden_tag().
Now that we've integrated CSRF protection, let's test it. Run the application and visit the homepage. You should see a login form:
<form method="POST">
<!-- ... -->
<input type="hidden" name="csrf_token" value="csrf_token_value" />
<!-- ... -->
</form>Try to submit the form with invalid credentials. You should be redirected to the login page with an error message. Now, let's simulate a CSRF attack by submitting the form using an attacker's script. The form submission should fail because of the CSRF protection.
What is the purpose of CSRF protection in Flask applications?