Python: Mention more sanitisation options in py/url-redirection qhelp.

This commit is contained in:
Max Schaefer
2023-12-19 17:31:45 +00:00
parent ff0c1ca2d6
commit 66fe32ab82
3 changed files with 39 additions and 3 deletions

View File

@@ -16,6 +16,10 @@ To guard against untrusted URL redirection, it is advisable to avoid putting use
directly into a redirect URL. Instead, maintain a list of authorized
redirects on the server; then choose from that list based on the user input provided.
</p>
<p>
If this is not possible, then the user input should be validated in some other way,
for example, by verifying that the target URL does not include an explicit host name.
</p>
</recommendation>
<example>
@@ -27,11 +31,29 @@ without validating the input, which facilitates phishing attacks:
<sample src="examples/redirect_bad.py"/>
<p>
One way to remedy the problem is to validate the user input against a known fixed string
before doing the redirection:
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:
</p>
<sample src="examples/redirect_good.py"/>
<p>
Often this is not possible, so an alternative is to check that the target URL does not
specify an explicit host name. For example, the Django framework provides a
function <code>url_has_allowed_host_and_scheme</code> that can be used to check that a
URL is safe to redirect to, as shown in the following example:
</p>
<sample src="examples/redirect_good2.py"/>
<p>
Note that many browsers accept backslash characters (<code>\</code>) as equivalent to
forward slash characters (<code>/</code>) in URLs, so it is important to account for this
when validating the URL, for example by first replacing all backslashes with forward
slashes. Django's <code>url_has_allowed_host_and_scheme</code> function
does this automatically, but other libraries may not.
</p>
</example>
<references>

View File

@@ -10,4 +10,5 @@ def hello():
if target == VALID_REDIRECT:
return redirect(target, code=302)
else:
... # Error
# ignore the target and redirect to the home page
return redirect('/', code=302)

View File

@@ -0,0 +1,13 @@
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('/')