Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions python/ql/src/Security/CWE-601/UrlRedirect.qhelp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down
3 changes: 2 additions & 1 deletion python/ql/src/Security/CWE-601/examples/redirect_good.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
13 changes: 13 additions & 0 deletions python/ql/src/Security/CWE-601/examples/redirect_good2.py
Original file line number Diff line number Diff line change
@@ -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('/')