Return-Path: Delivered-To: apmail-jakarta-tomcat-dev-archive@apache.org Received: (qmail 69184 invoked from network); 13 Mar 2002 07:42:26 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 13 Mar 2002 07:42:26 -0000 Received: (qmail 24934 invoked by uid 97); 13 Mar 2002 07:42:27 -0000 Delivered-To: qmlist-jakarta-archive-tomcat-dev@jakarta.apache.org Received: (qmail 24918 invoked by uid 97); 13 Mar 2002 07:42:26 -0000 Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Tomcat Developers List" Reply-To: "Tomcat Developers List" Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 24907 invoked by uid 97); 13 Mar 2002 07:42:26 -0000 Date: 13 Mar 2002 07:42:11 -0000 Message-ID: <20020313074211.65245.qmail@icarus.apache.org> From: remm@apache.org To: jakarta-tomcat-connectors-cvs@apache.org Subject: cvs commit: jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4 CoyoteConnector.java CoyoteProcessor.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N remm 02/03/12 23:42:11 Modified: coyote/src/java/org/apache/coyote/tomcat4 CoyoteConnector.java CoyoteProcessor.java Log: - Add the URI normalization code from TC 4 used to protect against some URI encoding based attacks. This may be useless in the HEAD branch after the proposed URI decoding refactoring is done, so this code can be disabled. It defaults to doing the checks, as some versions in the Tomcat 4.0.x branch are very likely to need it. Revision Changes Path 1.3 +32 -4 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java Index: CoyoteConnector.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- CoyoteConnector.java 27 Feb 2002 08:24:08 -0000 1.2 +++ CoyoteConnector.java 13 Mar 2002 07:42:11 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java,v 1.2 2002/02/27 08:24:08 remm Exp $ - * $Revision: 1.2 $ - * $Date: 2002/02/27 08:24:08 $ + * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java,v 1.3 2002/03/13 07:42:11 remm Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/13 07:42:11 $ * * ==================================================================== * @@ -103,7 +103,7 @@ * * @author Craig R. McClanahan * @author Remy Maucherat - * @version $Revision: 1.2 $ $Date: 2002/02/27 08:24:08 $ + * @version $Revision: 1.3 $ $Date: 2002/03/13 07:42:11 $ */ @@ -326,6 +326,12 @@ "org.apache.coyote.http11.Http11Processor"; + /** + * Use URI normalization. + */ + private boolean useURINormalizationHack = true; + + // ------------------------------------------------------------- Properties @@ -820,6 +826,28 @@ public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; + + } + + + /** + * Return the value of the Uri normalization flag. + */ + public boolean getUseURINormalizationHack() { + + return (this.useURINormalizationHack); + + } + + + /** + * Set the value of the Uri normalization flag. + * + * @param useURINormalizationHack The new flag value + */ + public void setUseURINormalizationHack(boolean useURINormalizationHack) { + + this.useURINormalizationHack = useURINormalizationHack; } 1.12 +102 -7 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteProcessor.java Index: CoyoteProcessor.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteProcessor.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- CoyoteProcessor.java 9 Mar 2002 17:40:01 -0000 1.11 +++ CoyoteProcessor.java 13 Mar 2002 07:42:11 -0000 1.12 @@ -1,6 +1,6 @@ -/* * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteProcessor.java,v 1.11 2002/03/09 17:40:01 remm Exp $ - * $Revision: 1.11 $ - * $Date: 2002/03/09 17:40:01 $ +/* * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteProcessor.java,v 1.12 2002/03/13 07:42:11 remm Exp $ + * $Revision: 1.12 $ + * $Date: 2002/03/13 07:42:11 $ * * ==================================================================== * @@ -112,7 +112,7 @@ * * @author Craig R. McClanahan * @author Remy Maucherat - * @version $Revision: 1.11 $ $Date: 2002/03/09 17:40:01 $ + * @version $Revision: 1.12 $ $Date: 2002/03/13 07:42:11 $ */ final class CoyoteProcessor @@ -301,7 +301,7 @@ try { // Parse and set Catalina and configuration specific // request parameters - postParseRequest(req); + postParseRequest(req, res); // Calling the container connector.getContainer().invoke(request, response); response.finishResponse(); @@ -370,7 +370,7 @@ /** * Parse additional request parameters. */ - protected void postParseRequest(Request req) + protected void postParseRequest(Request req, Response res) throws IOException { request.setSocket(socket); @@ -385,6 +385,17 @@ else request.setServerPort(serverPort); + // Normalize URI is needed for security reasons on older versions + // of Tomcat + if (connector.getUseURINormalizationHack()) { + String uri = normalize(request.getRequestURI()); + if (uri == null) { + res.setStatus(400); + res.setMessage("Invalid URI"); + throw new IOException("Invalid URI"); + } + } + parseHost(); parseSessionId(); parseCookies(); @@ -472,7 +483,7 @@ * Parse cookies. * Note: Using Coyote native cookie parser to parse cookies would be faster * but a conversion to Catalina own cookies would then be needed, which - * would take away most if not all of theperformance benefit. + * would take away most if not all of the performance benefit. */ protected void parseCookies() { @@ -501,6 +512,90 @@ request.addCookie(cookies[i]); } } + + } + + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements + * are present), return null instead. + * + * @param path Path to be normalized + */ + protected String normalize(String path) { + + if (path == null) + return null; + + // Create a place for the normalized path + String normalized = path; + + // Normalize "/%7E" and "/%7e" at the beginning to "/~" + if (normalized.startsWith("/%7E") || + normalized.startsWith("/%7e")) + normalized = "/~" + normalized.substring(4); + + // Prevent encoding '%', '/', '.' and '\', which are special reserved + // characters + if ((normalized.indexOf("%25") >= 0) + || (normalized.indexOf("%2F") >= 0) + || (normalized.indexOf("%2E") >= 0) + || (normalized.indexOf("%5C") >= 0) + || (normalized.indexOf("%2f") >= 0) + || (normalized.indexOf("%2e") >= 0) + || (normalized.indexOf("%5c") >= 0)) { + return null; + } + + if (normalized.equals("/.")) + return "/"; + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + return (null); // Trying to go outside our context + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Declare occurrences of "/..." (three or more dots) to be invalid + // (on some Windows platforms this walks the directory tree!!!) + if (normalized.indexOf("/...") >= 0) + return (null); + + // Return the normalized path that we have completed + return (normalized); } -- To unsubscribe, e-mail: For additional commands, e-mail: