It is common for web forms to redirect to a different page upon successful submission of the form data. This is often done using a next or return parameter in the HTTP request. Any HTTP parameter can be controlled by the user, and could be abused by attackers to redirect a user to a malicious site.
This is commonly used in phishing attacks, for example an attacker could redirect a user from a legitimate login form to a fake, attacker controlled, login form. If the page looks enough like the target site, and tricks the user into believing they mistyped their password, the attacker can convince the user to re-enter their credentials and send them to the attacker.
Here is an example of a malicious redirect URL:
To counter this type of attack all URLs must be validated before being used to redirect the user. This should ensure the redirect will take the user to a page within your site.
This example just processes the ‘next’ argument with no validation:
import os from flask import Flask,redirect, request app = Flask(__name__) @app.route('/') def example_redirect(): return redirect(request.args.get('next'))
The following is an example using the Flask web framework. It checks that the URL the user is being redirected to originates from the same host as the host serving the content.
from flask import request, g, redirect from urlparse import urlparse, urljoin def is_safe_redirect_url(target): host_url = urlparse(request.host_url) redirect_url = urlparse(urljoin(request.host_url, target)) return redirect_url.scheme in ('http', 'https') and \ host_url.netloc == redirect_url.netloc def get_safe_redirect(): url = request.args.get('next') if url and is_safe_redirect_url(url): return url url = request.referrer if url and is_safe_redirect_url(url): return url return '/'
The Django framework contains a django.utils.http.is_safe_url function that can be used to validate redirects without implementing a custom version.