marcsaeg 01/07/16 21:25:56 Modified: src/share/org/apache/tomcat/core Tag: tomcat_32 ContextManager.java src/share/org/apache/tomcat/request Tag: tomcat_32 AccessInterceptor.java src/share/org/apache/tomcat/util Tag: tomcat_32 URLUtil.java Log: This fixes several security related problems. 1) Non-normalized URIs bypass security-contraints 2) HTTP method (e.g. GET, POST, ...) comparisons in the AccessInterceptor were case sensitive. Thus, using telnet to issue "get /examples/jsp/security/protected/index.jsp" would bypass the security constraint, but "GET /examples/jsp/security/protected/index.jsp" would not. 3) Special chars (%25, %2e, %2f, %5c) in URIs are forbidden. PR: 2612 Revision Changes Path No revision No revision 1.100.2.26 +16 -1 jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java Index: ContextManager.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v retrieving revision 1.100.2.25 retrieving revision 1.100.2.26 diff -u -r1.100.2.25 -r1.100.2.26 --- ContextManager.java 2001/07/11 05:24:14 1.100.2.25 +++ ContextManager.java 2001/07/17 04:25:54 1.100.2.26 @@ -740,7 +740,22 @@ * XXX make sure the alghoritm is right, deal with response codes */ public void service( Request req, Response res ) { - internalService( req, res ); + + /** + * XXX Normalize and validate the request URI. This is important + * to prevent non-normalized URIs from causing security constraints + * from being bypassed. For example, /examples/jsp/../jsp/security/protected/index.jsp + * would not trigger the AccessInterceptor. Also, encoded special chars + * ., /, \ and % are forbidden in URIs to prevent additional security problems. + */ + req.setRequestURI(URLUtil.normalizeURI(req.getRequestURI())); + String ucURI = req.getRequestURI().toUpperCase(); + if(ucURI.indexOf("%25") >= 0 || ucURI.indexOf("%2E") >= 0 || + ucURI.indexOf("%2F") >= 0 || ucURI.indexOf("%5C") >=0){ + res.setStatus(404); + } + + internalService( req, res ); // clean up try { res.finish(); No revision No revision 1.12.2.9 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/request/Attic/AccessInterceptor.java Index: AccessInterceptor.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/Attic/AccessInterceptor.java,v retrieving revision 1.12.2.8 retrieving revision 1.12.2.9 diff -u -r1.12.2.8 -r1.12.2.9 --- AccessInterceptor.java 2001/07/15 23:09:31 1.12.2.8 +++ AccessInterceptor.java 2001/07/17 04:25:55 1.12.2.9 @@ -314,7 +314,7 @@ if( ctMethods != null && ctMethods.length > 0 ) { boolean ok=false; for( int i=0; i< ctMethods.length; i++ ) { - if( method.equals( ctMethods[i] ) ) { + if( method.equalsIgnoreCase( ctMethods[i] ) ) { ok=true; break; } No revision No revision 1.7.2.3 +90 -3 jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/URLUtil.java Index: URLUtil.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/URLUtil.java,v retrieving revision 1.7.2.2 retrieving revision 1.7.2.3 diff -u -r1.7.2.2 -r1.7.2.3 --- URLUtil.java 2001/04/08 01:37:57 1.7.2.2 +++ URLUtil.java 2001/07/17 04:25:55 1.7.2.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/URLUtil.java,v 1.7.2.2 2001/04/08 01:37:57 marcsaeg Exp $ - * $Revision: 1.7.2.2 $ - * $Date: 2001/04/08 01:37:57 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/URLUtil.java,v 1.7.2.3 2001/07/17 04:25:55 marcsaeg Exp $ + * $Revision: 1.7.2.3 $ + * $Date: 2001/07/17 04:25:55 $ * * ==================================================================== * @@ -205,4 +205,91 @@ return hasEscape; } + + // Based on Apache's path normalization code + public static String normalizeURI(String URI) + { + int start=0; + int end=URI.length(); + char buff[] = new char[URI.length()]; + URI.getChars(0, URI.length(), buff, 0); + int i=0; + int j=0; + + // remove // + for( i=start, j=start; i<end-1; i++ ) { + if( buff[i]== '/' && buff[i+1]=='/' ) { + while( buff[i+1]=='/' ) i++; + } + buff[j++]=buff[i]; + } + if( i!=j ) { + buff[j++]=buff[end-1]; + end=j; + } + + // remove /./ + for( i=start, j=start; i<end-1; i++ ) { + if( buff[i]== '.' && buff[i+1]=='/' && + ( i==0 || buff[i-1]=='/' )) { + // "/./" + i+=1; + if( i==end-1 ) j--; // cut the ending / + } else { + buff[j++]=buff[i]; + } + } + if( i!=j ) { + buff[j++]=buff[end-1]; + end=j; + } + + // remove /. at the end + j=end; + if( end==start+1 && buff[start]== '.' ) + end--; + else if( end > start+1 && buff[ end-1 ] == '.' && + buff[end-2]=='/' ) { + end=end-2; + } + + // remove /../ + for( i=start, j=start; i<end-2; i++ ) { + if( buff[i] == '.' && + buff[i+1] == '.' && + buff[i+2]== '/' && + ( i==0 || buff[ i-1 ] == '/' ) ) { + + i+=1; + // look for the previous / + j=j-2; + while( j>0 && buff[j]!='/' ) { + j--; + } + } else { + buff[j++]=buff[i]; + } + } + if( i!=j ) { + buff[j++]=buff[end-2]; + buff[j++]=buff[end-1]; + end=j; + } + + + // remove trailing xx/.. + j=end; + if( end>start + 3 && + buff[end-1]=='.' && + buff[end-2]=='.' && + buff[end-3]=='/' ) { + end-=4; + while( end>0 && buff[end]!='/' ) + end--; + } + + String result = new String(buff, 0, end); + return result; + } + }