summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-09-08 01:17:11 -0400
committerChris McDonough <chrism@plope.com>2011-09-08 01:17:11 -0400
commit05b8a60dc1e9bac7e8f7edd2a3f41f6bd8131307 (patch)
tree227fc54bae60c0e59a735ba0bf696da5cb264a43
parentd542103badc125214ef2a518245b93bb63d1642b (diff)
downloadpyramid-05b8a60dc1e9bac7e8f7edd2a3f41f6bd8131307.tar.gz
pyramid-05b8a60dc1e9bac7e8f7edd2a3f41f6bd8131307.tar.bz2
pyramid-05b8a60dc1e9bac7e8f7edd2a3f41f6bd8131307.zip
add additional oob tests and optimize _secure_path
-rw-r--r--pyramid/static.py15
-rw-r--r--pyramid/tests/test_integration.py5
-rw-r--r--pyramid/tests/test_static.py72
3 files changed, 78 insertions, 14 deletions
diff --git a/pyramid/static.py b/pyramid/static.py
index 08bade4b3..71534d09c 100644
--- a/pyramid/static.py
+++ b/pyramid/static.py
@@ -1,3 +1,4 @@
+import os
from os.path import normcase, normpath, join, getmtime, getsize, isdir, exists
from pkg_resources import resource_exists, resource_filename, resource_isdir
import mimetypes
@@ -132,9 +133,6 @@ class static_view(object):
path = _secure_path(path_tuple)
if path is None:
- # belt-and-suspenders security; this should never be true
- # unless someone screws up the traversal_path code
- # (request.subpath is computed via traversal_path too)
return HTTPNotFound('Out of bounds: %s' % request.url)
if self.package_name: # package resource
@@ -168,13 +166,16 @@ class static_view(object):
url = url + '?' + qs
return HTTPMovedPermanently(url)
-has_insecure_pathelement = set(['..', '.', '/', '']).intersection
+has_insecure_pathelement = set(['..', '.', '']).intersection
+contains_slash = set(['/', os.sep]).intersection
@lru_cache(1000)
def _secure_path(path_tuple):
if has_insecure_pathelement(path_tuple):
+ # belt-and-suspenders security; this should never be true
+ # unless someone screws up the traversal_path code
+ # (request.subpath is computed via traversal_path too)
+ return None
+ if any([contains_slash(item) for item in path_tuple]):
return None
- for item in path_tuple:
- if '../' in item:
- return None
return '/'.join([x.encode('utf-8') for x in path_tuple])
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index b78cddf4f..753a55d36 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -153,15 +153,10 @@ class TestStaticAppBase(IntegrationBase):
def test_oob_dotdotslash_encoded(self):
self.testapp.get('/static/%2E%2E%2F/test_integration.py', status=404)
- # XXX pdb this
def test_oob_slash(self):
self.testapp.get('/%2F/test_integration.py', status=404)
- def test_oob_dotdotslash_encoded(self):
- self.testapp.get('/static/%2E%2E%2F/test_integration.py', status=404)
-
-
class TestStaticAppUsingAbsPath(TestStaticAppBase, unittest.TestCase):
package = 'pyramid.tests.pkgs.static_abspath'
diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py
index 503552a8e..6dc38fc57 100644
--- a/pyramid/tests/test_static.py
+++ b/pyramid/tests/test_static.py
@@ -46,13 +46,47 @@ class Test_static_view_use_subpath_False(unittest.TestCase):
response = inst(context, request)
self.assertTrue('<html>static</html>' in response.body)
- def test_resource_out_of_bounds(self):
+ def test_oob_singledot(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO':'/./index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertTrue('<html>static</html>' in response.body)
+
+ def test_oob_emptyelement(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO':'//index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertTrue('<html>static</html>' in response.body)
+
+ def test_oob_dotdotslash(self):
inst = self._makeOne('pyramid.tests:fixtures/static')
request = self._makeRequest({'PATH_INFO':'/subdir/../../minimal.pt'})
context = DummyContext()
response = inst(context, request)
self.assertEqual(response.status, '404 Not Found')
+ def test_oob_dotdotslash_encoded(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest(
+ {'PATH_INFO':'/subdir/%2E%2E%2F%2E%2E/minimal.pt'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_oob_os_sep(self):
+ import os
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ dds = '..' + os.sep
+ request = self._makeRequest({'PATH_INFO':'/subdir/%s%sminimal.pt' %
+ (dds, dds)})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
def test_resource_doesnt_exist(self):
inst = self._makeOne('pyramid.tests:fixtures/static')
request = self._makeRequest({'PATH_INFO':'/notthere'})
@@ -168,7 +202,23 @@ class Test_static_view_use_subpath_True(unittest.TestCase):
response = inst(context, request)
self.assertTrue('<html>static</html>' in response.body)
- def test_resource_out_of_bounds(self):
+ def test_oob_singledot(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('.', 'index.html')
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_oob_emptyelement(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('', 'index.html')
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_oob_dotdotslash(self):
inst = self._makeOne('pyramid.tests:fixtures/static')
request = self._makeRequest()
request.subpath = ('subdir', '..', '..', 'minimal.pt')
@@ -176,6 +226,24 @@ class Test_static_view_use_subpath_True(unittest.TestCase):
response = inst(context, request)
self.assertEqual(response.status, '404 Not Found')
+ def test_oob_dotdotslash_encoded(self):
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('subdir', '%2E%2E', '%2E%2E', 'minimal.pt')
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_oob_os_sep(self):
+ import os
+ inst = self._makeOne('pyramid.tests:fixtures/static')
+ dds = '..' + os.sep
+ request = self._makeRequest()
+ request.subpath = ('subdir', dds, dds, 'minimal.pt')
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
def test_resource_doesnt_exist(self):
inst = self._makeOne('pyramid.tests:fixtures/static')
request = self._makeRequest()