CSRF attacks occur when a malicious website tricks a user’s browser into making requests to another website where the user is authenticated. For example, if a user is logged into their online banking account and visits a malicious website, the malicious site can send requests to the banking website on behalf of the user without the user’s knowledge or consent.
Flask provides CSRF protection through the flask_wtf.csrf.CSRFProtect
extension. This extension works by generating a unique CSRF token for each user session. When a user makes a request to a protected route (usually a POST, PUT, DELETE, etc. request), the server checks if the CSRF token in the request matches the one stored in the session. If they match, the request is considered valid; otherwise, it is rejected.
When users submit forms on a Flask application, such as a login form, registration form, or a form to update user information, CSRF protection should be enabled. This ensures that the form submissions are coming from the legitimate application and not from a malicious source.
For RESTful APIs that handle sensitive operations like deleting user accounts or making financial transactions, CSRF protection is essential. It prevents attackers from tricking users into making unauthorized API calls.
from flask import Flask
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
# Set a secret key for session management, which is required for CSRF protection
app.config['SECRET_KEY'] = 'your_secret_key'
# Initialize CSRF protection
csrf = CSRFProtect(app)
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
In this example, we first import the necessary modules. We create a Flask application and set a secret key, which is required for session management and CSRF protection. Then we initialize the CSRFProtect
extension with our Flask application.
from flask import Flask, render_template, request
from flask_wtf.csrf import CSRFProtect
from wtforms import Form, StringField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
csrf = CSRFProtect(app)
class MyForm(Form):
name = StringField('Name')
@app.route('/form', methods=['GET', 'POST'])
def form():
form = MyForm(request.form)
if request.method == 'POST' and form.validate():
name = form.name.data
return f'Hello, {name}!'
return render_template('form.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
In the HTML template (form.html
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Form</title>
</head>
<body>
<form method="post">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name() }}
<input type="submit" value="Submit">
</form>
</body>
</html>
In the Python code, we define a form class using wtforms
. In the route function, we handle both GET and POST requests. In the HTML template, we include the CSRF token using {{ form.csrf_token }}
.
Without a secret key, Flask’s session management and CSRF protection will not work correctly. The secret key is used to sign the session cookie and generate CSRF tokens.
Sometimes, developers may disable CSRF protection globally for convenience during development. However, this leaves the application vulnerable to CSRF attacks in production.
If the CSRF token is not included in HTML forms, the form submissions will be rejected by the server.
Always use HTTPS in production to encrypt the data transmitted between the client and the server. This helps prevent attackers from intercepting and modifying CSRF tokens.
Instead of protecting all routes, limit CSRF protection to routes that handle sensitive operations like form submissions and API endpoints.
Keep the Flask and flask_wtf
packages up - to - date to ensure that you have the latest security patches.
Flask CSRF protection is a powerful tool to safeguard your web application from CSRF attacks. By understanding the core concepts, using it in typical scenarios, avoiding common pitfalls, and following best practices, you can ensure the security and integrity of your Flask application.