summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorianb <devnull@localhost>2006-12-18 00:28:21 +0000
committerianb <devnull@localhost>2006-12-18 00:28:21 +0000
commit7c0b1546341ae5761701c4d667cbb6e87327ba19 (patch)
treeed070f240b8a249e2e407eecb1993ed558a58682
parent165668aae8890fba08a5b40a83a814e4c74bf659 (diff)
downloadpaste-7c0b1546341ae5761701c4d667cbb6e87327ba19.tar.gz
Security fix for StaticURLParser, plus unquote SCRIPT_NAME and PATH_INFO, plus don't double-unquote in StaticURLParser
-rw-r--r--docs/news.txt10
-rwxr-xr-xpaste/httpserver.py5
-rw-r--r--paste/urlparser.py12
-rw-r--r--paste/wsgilib.py2
4 files changed, 21 insertions, 8 deletions
diff --git a/docs/news.txt b/docs/news.txt
index 71e925e..6517f0c 100644
--- a/docs/news.txt
+++ b/docs/news.txt
@@ -6,6 +6,16 @@ News
svn trunk
---------
+* Security fix for ``paste.urlparser.StaticURLParser``. The problem
+ allowed escaping the root (and reading files) when used with
+ ``paste.httpserver`` (this does not effect other servers, and does
+ not apply when proxying requests from Apache to
+ ``paste.httpserver``).
+
+* ``paste.httpserver`` and ``paste.fixture.TestApp`` url-unquote
+ ``SCRIPT_NAME`` and ``PATH_INFO``, as specified in the CGI spec.
+ Thanks to Jon Nelson for pointing out both these issues.
+
* ``paste.registry`` now works within the ``EvalException``
interactive debugger.
diff --git a/paste/httpserver.py b/paste/httpserver.py
index 518bb21..bbd4913 100755
--- a/paste/httpserver.py
+++ b/paste/httpserver.py
@@ -17,7 +17,8 @@ if pyOpenSSL is installed, it also provides SSL capabilities.
# @@: add support for chunked encoding, this is not a 1.1 server
# till this is completed.
-import socket, sys, threading, urlparse, Queue
+import socket, sys, threading, urlparse, Queue, urllib
+import posixpath
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
from paste.util import converters
@@ -160,6 +161,8 @@ class WSGIHandlerMixin:
"""
(_, _, path, query, fragment) = urlparse.urlsplit(self.path)
+ path = urllib.unquote(path)
+ path = posixpath.normpath(path)
(server_name, server_port) = self.server.server_address
rfile = self.rfile
diff --git a/paste/urlparser.py b/paste/urlparser.py
index 6aa5105..1e27a05 100644
--- a/paste/urlparser.py
+++ b/paste/urlparser.py
@@ -7,7 +7,6 @@ WSGI applications that parse the URL and dispatch to on-disk resources
import os
import sys
import imp
-import urllib
import pkg_resources
import mimetypes
from paste import request
@@ -203,8 +202,7 @@ class URLParser(object):
# None of the index files found
filename = None
else:
- # Handle quoted chars (e.g. %20)
- filename = self.find_file(environ, urllib.unquote(name))
+ filename = self.find_file(environ, name)
if filename is None:
return None, filename
else:
@@ -435,6 +433,8 @@ class StaticURLParser(object):
self.root_directory = root_directory
if root_directory is not None:
self.root_directory = os.path.normpath(self.root_directory)
+ else:
+ self.root_directory = directory
self.cache_max_age = cache_max_age
def __call__(self, environ, start_response):
@@ -445,8 +445,7 @@ class StaticURLParser(object):
# @@: This should obviously be configurable
filename = 'index.html'
else:
- # Handle quoted chars (e.g. %20)
- filename = urllib.unquote(request.path_info_pop(environ))
+ filename = request.path_info_pop(environ)
full = os.path.normpath(os.path.join(self.directory, filename))
if self.root_directory is not None and not full.startswith(self.root_directory):
# Out of bounds
@@ -550,8 +549,7 @@ class PkgResourcesParser(StaticURLParser):
# @@: This should obviously be configurable
filename = 'index.html'
else:
- # Handle quoted chars (e.g. %20)
- filename = urllib.unquote(request.path_info_pop(environ))
+ filename = request.path_info_pop(environ)
resource = os.path.normpath(self.resource_name + '/' + filename)
if self.root_resource is not None and not resource.startswith(self.root_resource):
# Out of bounds
diff --git a/paste/wsgilib.py b/paste/wsgilib.py
index 234f7cc..82a91f0 100644
--- a/paste/wsgilib.py
+++ b/paste/wsgilib.py
@@ -13,6 +13,7 @@ from paste.response import HeaderDict, has_header, header_value, remove_header
from paste.response import error_body_response, error_response, error_response_app
from traceback import print_exception
+import urllib
from cStringIO import StringIO
import sys
from urlparse import urlsplit
@@ -303,6 +304,7 @@ def raw_interactive(application, path='', raise_on_wsgi_error=False,
}
if path:
(_, _, path_info, query, fragment) = urlsplit(str(path))
+ path_info = urllib.unquote(path_info)
basic_environ['PATH_INFO'] = path_info
if query:
basic_environ['QUERY_STRING'] = query