Django check: Open redirect

When input data from request is passed to redirect(), it is an open redirect and could be exploited. See CWE 601 for more information.

Description

Open URL redirects are considered unvalidated redirects and forwards by OWASP.

When redirect() uses an unsanitized or unvalidated URL input paramater, a remote attacker may successfully launch a phishing scam and steal user credentials by modifying the URL input to a malicious site.

Because the server name in the modified link is identical to the original site, phishing attempts may have a more trustworthy appearance. Unvalidated redirect and forward attacks can also be used to maliciously craft a URL that would pass the application's access control check and then forward the attacker to privileged functions that they would normally not be able to access.

This check will alert on these cases, for example:

from django.shortcuts import redirect
from django.http import HttpResponseRedirect

def unsafe(request):
    # referrer request header is directly passed to redirect function
    # this is an open request vulnerability
    url = request.headers.get('referrer')
    print("something")
    return redirect(url)

def unsafe2(request):
    # url from the post request is directly passed to redirect function
    # this is an open request vulnerability
    url = request.POST.get("url")
    return HttpResponseRedirect(url)

This check will not alert on these cases, for example:

from django.shortcuts import redirect
from django.http import HttpResponseRedirect

def safe(request):
    # redirect paramater is not coming from the request
    url = "https://lmnop.qrs"
    return redirect(url)

References

  1. OWASP cheatsheet
  2. CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
  3. Stackoverflow: best way to avoid Open Redirects in django
  4. Django documentation