]> granicus.if.org Git - python/commitdiff
[Bug #1473048]
authorAndrew M. Kuchling <amk@amk.ca>
Wed, 31 May 2006 14:08:48 +0000 (14:08 +0000)
committerAndrew M. Kuchling <amk@amk.ca>
Wed, 31 May 2006 14:08:48 +0000 (14:08 +0000)
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.

Doc/lib/libsimplexmlrpc.tex
Lib/DocXMLRPCServer.py
Lib/SimpleXMLRPCServer.py

index a25cabf6d58111f621ab2b078c7329e9c6d14d08..7a9786125d58b41a30ab5698119b04a0956b28d5 100644 (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}
index 259fb18b8631ad38ca47d84402c5d8da8d55bada..86ed32b6fc193248bb791c68e01ac95fd0e745bc 100644 (file)
@@ -227,6 +227,10 @@ class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
         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)
index db7749a14f052b9b0d0d7b3f0e01aac74c279f66..c7646cf2cce28764cfc6557bf20bf0f40094cfc2 100644 (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 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
         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 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             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."""