Skip to content

Harden django.shortcuts.redirect to validate redirect URL #97

@RealOrangeOne

Description

@RealOrangeOne

Code of Conduct

  • I agree to follow Django's Code of Conduct

Feature Description

I suggest extending the redirect shortcut with a few additional (opt-in) arguments to validate the URL being redirected to. Notably:

  • allowed_hosts, to specify hosts that the URL can be redirected to (or [] to require only a path-based redirect)
  • require_https, to ensure the redirect stays secure

Following that validation, iri_to_uri would be run on the path to ensure it's correctly encoded before being passed to the response.

Problem

Following a conversation on the forum, it was noted that Django's url_has_allowed_host_and_scheme is an internal API, despite being a core piece of functionality when validating a user's redirect API (eg the next query param).

def my_view(request):
    next_url = request.GET.get('next')
    
    if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=["example.com"], require_https=request.is_secure()):
        return redirect(next_url)
    
    return redirect("/")

I believe this pattern performs all the validation, however it's easy to mess up:

  • url_has_allowed_host_and_scheme isn't publicly documented, therefore has no stability guarantees (sort of)
  • Someone could easily skip redirect and just build a HttpResponse and set a Location header on it (unlikely, but probably happens)
  • People may forget that it's possible redirect https -> http.

Request or proposal

proposal

Additional Details

As Carlton correctly points out on the forum thread, validation is multi-step, and you need all of them to pass. That's why I don't think making url_has_allowed_host_and_scheme public is necessarily the right solution. Instead, a single public API ensures all steps of the validation are performed, so one can't be missed or forgotten.

Implementation Suggestions

Many of the building blocks are already there in url_has_allowed_host_and_scheme, they just need to be used.

If not passed, the validation should not be applied, so as not to be a breaking change to redirect.


These thoughts are my own, and not necessarily of the wider Security Team.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Idea

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions