access icon indicating copy to clipboard operation
access copied to clipboard

fix: URL redirection from authenticate_user

Open odaysec opened this issue 8 months ago • 0 comments

fix the problem to validate the user-provided URL before using it in the redirection. We can use the urlparse function from the Python standard library to parse the URL and check that it does not include an explicit host name. This ensures that only relative paths within the application's domain are allowed for redirection. modify the authenticate_user method in the AuthenticationHelpers class to include this validation. Specifically, we will replace the current redirection logic with a check that ensures the next parameter in the URL is a relative path.

Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.

POC

The following vulnerable shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks:

from flask import Flask, request, redirect

app = Flask(__name__)

@app.route('/')
def hello():
    target = request.args.get('target', '')
    return redirect(target, code=302)

If you know the set of valid redirect targets, you can maintain a list of them on the server and check that the user input is in that list:

from flask import Flask, request, redirect

VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"

app = Flask(__name__)

@app.route('/')
def hello():
    target = request.args.get('target', '')
    if target == VALID_REDIRECT:
        return redirect(target, code=302)
    else:
        # ignore the target and redirect to the home page
        return redirect('/', code=302)

Often this is not possible, so an alternative is to check that the target URL does not specify an explicit host name. For example, you can use the urlparse function from the Python standard library to parse the URL and check that the netloc attribute is empty.

from flask import Flask, request, redirect
from urllib.parse import urlparse

app = Flask(__name__)

@app.route('/')
def hello():
    target = request.args.get('target', '')
    target = target.replace('\\', '')
    if not urlparse(target).netloc and not urlparse(target).scheme:
        # relative path, safe to redirect
        return redirect(target, code=302)
    # ignore the target and redirect to the home page
    return redirect('/', code=302)

For Django application, you can use the function url_has_allowed_host_and_scheme to check that a URL is safe to redirect to, as shown in the following code:

from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.utils.http import url_has_allowed_host_and_scheme
from django.views import View

class RedirectView(View):
    def get(self, request, *args, **kwargs):
        target = request.GET.get('target', '')
        if url_has_allowed_host_and_scheme(target, allowed_hosts=None):
            return HttpResponseRedirect(target)
        else:
            # ignore the target and redirect to the home page
            return redirect('/')

References

XSS Unvalidated Redirects and Forwards Cheat Sheet urllib.parse CWE-601

odaysec avatar Apr 10 '25 17:04 odaysec