django / django/new-features

Harden `django.shortcuts.redirect` to validate redirect URL

Open
#97 2 comments 7 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
188
Forks
7
PR merge metrics
No merged PRs in 30d

Description

### Code of Conduct

- [x] 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](https://forum.djangoproject.com/t/why-is-the-use-of-url-has-allowed-host-and-scheme-discouraged/35314), 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).

```python
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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.