SimpleXMLRPCServer and DocXMLRPCServer don't look at
the path of the HTTP request at all; you can POST or
GET from / or /RPC2 or /blahblahblah with the same results.
Security scanners that look for /cgi-bin/phf will therefore report
lots of vulnerabilities.

Fix: add a .rpc_paths attribute to the SimpleXMLRPCServer class,
and report a 404 error if the path isn't on the allowed list.

Possibly-controversial aspect of this change: the default makes only
'/' and '/RPC2' legal.  Maybe this will break people's applications
(though I doubt it).  We could just set the default to an empty tuple,
which would exactly match the current behaviour.
This commit is contained in:
Andrew M. Kuchling 2006-05-31 14:08:48 +00:00
parent bc09e1086e
commit 622f144175
3 changed files with 41 additions and 0 deletions

View file

@ -111,6 +111,15 @@ simple, stand alone XML-RPC servers.
Registers the XML-RPC multicall function system.multicall.
\end{methoddesc}
\begin{memberdesc}[SimpleXMLRPCServer]{rpc_paths}
An attribute value that must be a tuple listing valid path portions of
the URL for receiving XML-RPC requests. Requests posted to other
paths will result in a 404 ``no such page'' HTTP error. If this
tuple is empty, all paths will be considered valid.
The default value is \code{('/', '/RPC2')}.
\versionadded{2.5}
\end{memberdesc}
Example:
\begin{verbatim}

View file

@ -227,6 +227,10 @@ def do_GET(self):
Interpret all HTTP GET requests as requests for server
documentation.
"""
# Check that the path is legal
if not self.is_rpc_path_valid():
self.report_404()
return
response = self.server.generate_html_documentation()
self.send_response(200)

View file

@ -423,6 +423,17 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
XML-RPC requests.
"""
# Class attribute listing the accessible path components;
# paths not on this list will result in a 404 error.
rpc_paths = ('/', '/RPC2')
def is_rpc_path_valid(self):
if self.rpc_paths:
return self.path in self.rpc_paths
else:
# If .rpc_paths is empty, just assume all paths are legal
return True
def do_POST(self):
"""Handles the HTTP POST request.
@ -430,6 +441,11 @@ def do_POST(self):
which are forwarded to the server's _dispatch method for handling.
"""
# Check that the path is legal
if not self.is_rpc_path_valid():
self.report_404()
return
try:
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
@ -468,6 +484,18 @@ def do_POST(self):
self.wfile.flush()
self.connection.shutdown(1)
def report_404 (self):
# Report a 404 error
self.send_response(404)
response = 'No such page'
self.send_header("Content-type", "text/plain")
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
# shut down the connection
self.wfile.flush()
self.connection.shutdown(1)
def log_request(self, code='-', size='-'):
"""Selectively log an accepted request."""