If your Flask application uses a next parameter to redirect users after login, you might be vulnerable to Open Redirects.
This is a subtle but dangerous vulnerability where an attacker manipulates your site to redirect users to a malicious phishing page. Because the link starts with your trusted domain, users are more likely to click it.
The Vulnerability Explained
Imagine your login logic looks like this:
# VULNERABLE CODE
@app.route('/login', methods=['POST'])
def login():
# ... verify credentials ...
next_page = request.args.get('next')
return redirect(next_page or url_for('home'))
An attacker can craft a URL like:
https://yoursite.com/login?next=http://malicious-site.com/steal-credentials
When the user logs in, your server happily redirects them to malicious-site.com. The user, thinking they are still in your trusted workflow, might re-enter their password on the fake site.
The Fix: Validating the Target URL
To prevent this, we must ensure that the next URL is safe. A “safe” URL is either:
1. Relative: Starts with a / (e.g., /dashboard).
2. Internal: Has the same host/domain as your application.
We can write a robust helper function using Python’s urllib.parse.
The is_safe_url Helper
from urllib.parse import urlparse, urljoin
from flask import request
def is_safe_url(target):
"""
Ensures a redirect target is safe (internal).
"""
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return (
test_url.scheme in ('http', 'https') and
ref_url.netloc == test_url.netloc
)
Implementing the Secure Redirect
Now, update your view function to use this check:
@app.route('/login', methods=['POST'])
def login():
# ... verify credentials ...
next_page = request.args.get('next')
# SECURITY CHECK
if not next_page or not is_safe_url(next_page):
next_page = url_for('home')
return redirect(next_page)
How It Works
urljoin: We useurljointo handle relative paths correctly. Iftargetis just/dashboard, it resolves tohttp://yoursite.com/dashboard.urlparse: This breaks the URL into components (scheme, netloc, path).netlocCheck: We compare the network location (domain) of the request with the target. If they don’t match, it’s an external link, and we block it.
Summary
The “Open Redirect” is a classic OWASP vulnerability that is easy to introduce but also easy to fix.
Rule of Thumb: Never trust user input, especially when it dictates where the browser should go next. Always validate the next parameter against your own domain whitelist.
Written by
Abdur-Rahmaan Janhangeer
Chef
Python author of 9+ years having worked for Python companies around the world
Suggested Posts
How to correctly use the next parameter in login and logout in Flask
Here is a sample login and logout route taken from the shopyo web framework. You can learn here how ...
How to disable csrf protection for particular routes in Flask-wtf
Flask-wtf recommends using @csrf.exempt to disable csrf protection for particular routes as in the c...
Why Choose Flask Over FastAPI
FastAPI positions itself as one of the best choices for API development in Python. The project is po...