PYTHON

Protecting Against Cross-Site Request Forgery (CSRF) with Tokens

Safeguard your web application from CSRF attacks by implementing and validating anti-CSRF tokens in forms and AJAX requests on the server-side.

from flask import Flask, render_template_string, request, session, redirect, url_for, flash
import secrets # For generating secure tokens

app = Flask(__name__)
# CRITICAL: Replace with a strong, randomly generated secret key in production
app.secret_key = secrets.token_hex(16) 

def generate_csrf_token():
    # Generate a new token if one doesn't exist in the session
    if '_csrf_token' not in session:
        session['_csrf_token'] = secrets.token_hex(32)
    return session['_csrf_token']

# Make the CSRF token available globally in Jinja templates
app.jinja_env.globals['csrf_token'] = generate_csrf_token

@app.before_request
def csrf_protect():
    if request.method == "POST":
        # Retrieve token from session and form data
        session_token = session.pop('_csrf_token', None) # Pop to ensure one-time use or regeneration
        form_token = request.form.get('_csrf_token')

        # Validate tokens
        if not session_token or session_token != form_token:
            flash("CSRF token missing or incorrect.", "error")
            # In a real application, you might abort(403) or redirect to an error page
            return redirect(url_for('login_page')) 
    
    # Always regenerate the token for the next request (GET or valid POST)
    session['_csrf_token'] = secrets.token_hex(32)

@app.route('/login', methods=['GET', 'POST'])
def login_page():
    if request.method == 'POST':
        # Simulated login logic
        username = request.form['username']
        password = request.form['password']
        if username == 'user' and password == 'pass': # Use secure password hashing in production!
            flash('Logged in successfully!', 'success')
            return redirect(url_for('dashboard_page'))
        flash('Invalid credentials.', 'error')

    # Minimal HTML template for demonstration
    html_template = "<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta charset=\"UTF-8\">
    <title>Login</title>
</head>
<body>
    {% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        <ul class=\"flashes\">
        {% for category, message in messages %}
            <li class=\"{{ category }}\">{{ message }}</li>
        {% endfor %}
        </ul>
    {% endif %}
    {% endwith %}
    <form method=\"post\" action=\"{{ url_for('login_page') }}\">
        <input type=\"hidden\" name=\"_csrf_token\" value=\"{{ csrf_token() }}\">
        <label for=\"username\">Username:</label>
        <input type=\"text\" id=\"username\" name=\"username\"><br>
        <label for=\"password\">Password:</label>
        <input type=\"password\" id=\"password\" name=\"password\"><br>
        <input type=\"submit\" value=\"Login\">
    </form>
</body>
</html>"
    return render_template_string(html_template)

@app.route('/dashboard')
def dashboard_page():
    return "Welcome to the secure dashboard!"

if __name__ == '__main__':
    app.run(debug=True) # Set debug=False in production
How it works: Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to submit a request to a web application against which they are currently authenticated. This Python Flask snippet demonstrates a common defense: using anti-CSRF tokens. A unique token is generated and stored in the user's session and also included as a hidden field in forms. On submission, the server verifies that the token from the form matches the one in the session. If they don't match, the request is rejected, preventing malicious requests initiated from other sites. The token is regenerated after each successful POST request for added security.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs