diff --git a/VERSION b/VERSION index 223bb037..a83a70cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-12-03 13:15:15) stable +Version 2.2.1 (2012-12-03 14:03:31) stable diff --git a/gluon/rewrite.py b/gluon/rewrite.py index 9ec13e0e..629de0fb 100644 --- a/gluon/rewrite.py +++ b/gluon/rewrite.py @@ -55,7 +55,9 @@ regex_space = re.compile('(\+|\s|%20)+') # file and args may also contain '-', '=', '.' and '/' # apps in routes_apps_raw must parse raw_args into args -regex_url = re.compile('^/((?P\w+)(/(?P\w+)(/(?P(?P\w+)(\.(?P[\w.]+))?(?P[/\w@=-]*(\.[/\w@=-]+)*)))?)?)?$') +regex_url = re.compile('^/((?P\w+)(/(?P\w+)(/(?P(?P\w+)(\.(?P[\w.]+))?(?P.*)))?)?)?$') +regex_args = re.compile('^[/\w@=-]*(\.[/\w@=-]+)*$') + def _router_default(): "return new copy of default base router" @@ -604,6 +606,10 @@ def regex_filter_in(e): def sluggify(key): return key.lower().replace('.', '_') +def invalid_url(routes): + raise HTTP(400, + routes.error_message % 'invalid request', + web2py_error='invalid path') def regex_url_in(request, environ): "rewrite and parse incoming URL" @@ -631,18 +637,21 @@ def regex_url_in(request, environ): path = path[:-1] match = regex_url.match(path) if not match: - raise HTTP(400, - routes.error_message % 'invalid request', - web2py_error='invalid path') - elif match.group('c') == 'static': + invalid_url(routes) + request.raw_args = (match.group('s') or '') + if request.raw_args.startswith('/'): + request.raw_args = request.raw_args[1:] + if match.group('c') == 'static': application = match.group('a') version, filename = None, match.group('z') items = filename.split('/', 1) if regex_version.match(items[0]): version, filename = items - static_file = pjoin(request.env.applications_parent, - 'applications', application, - 'static', filename) + static_folder = pjoin(request.env.applications_parent, + 'applications', application,'static') + static_file = os.path.abspath(pjoin(static_folder,filename)) + if not static_file.startswith(static_folder): + invalid_url(routes) return (static_file, version, environ) else: # ################################################## @@ -653,12 +662,13 @@ def regex_url_in(request, environ): request.function = match.group('f') or routes.default_function request.raw_extension = match.group('e') request.extension = request.raw_extension or 'html' - request.raw_args = match.group('s') if request.application in routes.routes_apps_raw: # application is responsible for parsing args request.args = None + elif not regex_args.match(request.raw_args): + invalid_url(routes) elif request.raw_args: - request.args = List(request.raw_args.split('/')[1:]) + request.args = List(request.raw_args.split('/')) else: request.args = List([]) return (None, None, environ) diff --git a/gluon/tests/test_routes.py b/gluon/tests/test_routes.py index 675371ab..3a278659 100644 --- a/gluon/tests/test_routes.py +++ b/gluon/tests/test_routes.py @@ -105,13 +105,16 @@ class TestRoutes(unittest.TestCase): self.assertEqual(filter_url( 'http://domain.com/abc/def/ghi/j%20kl'), "/abc/def/ghi ['j_kl']") self.assertEqual(filter_url('http://domain.com/welcome/static/path/to/static'), "%s/applications/welcome/static/path/to/static" % root) + # no more necessary since explcit check for directory traversal attacks + """ self.assertRaises(HTTP, filter_url, 'http://domain.com/welcome/static/bad/path/to/st~tic') try: # 2.7+ only self.assertRaisesRegexp(HTTP, "400.*BAD REQUEST \[invalid path\]", filter_url, 'http://domain.com/welcome/static/bad/path/to/st~tic') except AttributeError: pass - # outgoing + """ + # outgoing self.assertEqual(filter_url('http://domain.com/init/default/index', out=True), '/init/default/index') self.assertEqual(filter_url('http://domain.com/init/default/index/arg1', out=True), '/init/default/index/arg1')