diff options
author | ianb <devnull@localhost> | 2006-12-18 00:28:21 +0000 |
---|---|---|
committer | ianb <devnull@localhost> | 2006-12-18 00:28:21 +0000 |
commit | 7c0b1546341ae5761701c4d667cbb6e87327ba19 (patch) | |
tree | ed070f240b8a249e2e407eecb1993ed558a58682 | |
parent | 165668aae8890fba08a5b40a83a814e4c74bf659 (diff) | |
download | paste-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.txt | 10 | ||||
-rwxr-xr-x | paste/httpserver.py | 5 | ||||
-rw-r--r-- | paste/urlparser.py | 12 | ||||
-rw-r--r-- | paste/wsgilib.py | 2 |
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 |