Validate redirect target in TrailingSlashHandler

Fixes open redirect vulnerability GHSA-c7vm-f5p4-8fqh
This commit is contained in:
Min RK 2020-10-15 09:39:44 +02:00 committed by Kevin Bates
parent 5a73a8e402
commit 1abd95130c
No known key found for this signature in database
GPG Key ID: ADCCD5840EE5145F
2 changed files with 28 additions and 4 deletions

View File

@ -853,13 +853,18 @@ class APIVersionHandler(APIHandler):
class TrailingSlashHandler(web.RequestHandler):
"""Simple redirect handler that strips trailing slashes
This should be the first, highest priority handler.
"""
def get(self):
self.redirect(self.request.uri.rstrip('/'))
path, *rest = self.request.uri.partition("?")
# trim trailing *and* leading /
# to avoid misinterpreting repeated '//'
path = "/" + path.strip("/")
new_uri = "".join([path, *rest])
self.redirect(new_uri)
post = put = get
@ -910,6 +915,7 @@ class RedirectWithParams(web.RequestHandler):
url = sep.join([self._url, self.request.query])
self.redirect(url, permanent=self._permanent)
class PrometheusMetricsHandler(IPythonHandler):
"""
Return prometheus metrics for this notebook server

View File

@ -2,10 +2,13 @@
import re
from notebook.base.handlers import path_regex
from notebook.utils import url_path_join
from .launchnotebook import NotebookTestBase
# build regexps that tornado uses:
path_pat = re.compile('^' + '/x%s' % path_regex + '$')
def test_path_regex():
for path in (
'/x',
@ -29,3 +32,18 @@ def test_path_regex_bad():
'/y/x/foo',
):
assert not re.match(path_pat, path)
class RedirectTestCase(NotebookTestBase):
def test_trailing_slash(self):
for uri, expected in (
("/notebooks/mynotebook/", "/notebooks/mynotebook"),
("////foo///", "/foo"),
("//example.com/", "/example.com"),
("/has/param/?hasparam=true", "/has/param?hasparam=true"),
):
r = self.request("GET", uri, allow_redirects=False)
print(uri, expected)
assert r.status_code == 302
assert "Location" in r.headers
assert r.headers["Location"] == url_path_join(self.url_prefix, expected)