Return-Path: Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 33054 invoked by uid 500); 12 Dec 2000 01:01:07 -0000 Delivered-To: apmail-jakarta-tomcat-cvs@apache.org Received: (qmail 33051 invoked by uid 1059); 12 Dec 2000 01:01:07 -0000 Date: 12 Dec 2000 01:01:07 -0000 Message-ID: <20001212010107.33050.qmail@locus.apache.org> From: craigmcc@locus.apache.org To: jakarta-tomcat-cvs@apache.org Subject: cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util SessionIdGenerator.java SessionUtil.java craigmcc 00/12/11 17:01:06 Modified: . Tag: TOMCAT_31_BRANCH build.xml src/admin/WEB-INF Tag: TOMCAT_31_BRANCH web.xml src/etc Tag: TOMCAT_31_BRANCH web.xml src/examples/WEB-INF Tag: TOMCAT_31_BRANCH web.xml src/examples/WEB-INF/classes/examples Tag: TOMCAT_31_BRANCH ShowSource.java src/share/org/apache/jasper/runtime Tag: TOMCAT_31_BRANCH JspServlet.java src/share/org/apache/tomcat/service/connector Tag: TOMCAT_31_BRANCH Ajp12ConnectionHandler.java src/share/org/apache/tomcat/servlets Tag: TOMCAT_31_BRANCH DefaultServlet.java src/share/org/apache/tomcat/util Tag: TOMCAT_31_BRANCH SessionIdGenerator.java SessionUtil.java Log: Fixes for security vulnerabilities in Tomcat 3.1 (final), and proposed release notes for a Tomcat 3.1.1 maintenance release that *only* fixes the security related problems. The identified (and fixed) vulnerabilities are: - Administrative application enabled by default (removed) - Case insensitive matches on static files under Windows - Snoop servlet mappings in example application - JSP "Show Source" could show WEB-INF files - Requesting unknown JSP pages showed disk file pathname - Session ID generation algorithm subject to attack (replaced with the algorithm from 3.2). - Tomcat 3.1 could be shut down remotely. See separate commits for security issues related to 3.2, and discussion of recommended course of action. Revision Changes Path No revision No revision 1.44.4.1 +6 -0 jakarta-tomcat/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/jakarta-tomcat/build.xml,v retrieving revision 1.44 retrieving revision 1.44.4.1 diff -u -r1.44 -r1.44.4.1 --- build.xml 2000/04/05 03:16:15 1.44 +++ build.xml 2000/12/12 01:00:59 1.44.4.1 @@ -91,11 +91,13 @@ classpath="${tomcat.build}/classes"/> + @@ -126,6 +128,7 @@ includes="org/apache/jasper/**"/> + @@ -147,10 +151,12 @@ includes="**" /> + + + + + /* + + + admin + + + + + BASIC + Tomcat Administrative Application + + No revision No revision 1.1.6.1 +12 -0 jakarta-tomcat/src/etc/web.xml Index: web.xml =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/etc/web.xml,v retrieving revision 1.1 retrieving revision 1.1.6.1 diff -u -r1.1 -r1.1.6.1 --- web.xml 2000/02/09 23:26:28 1.1 +++ web.xml 2000/12/12 01:01:01 1.1.6.1 @@ -12,6 +12,18 @@ org.apache.tomcat.servlets.DefaultServlet + + + caseSensitive + + + true + + + Set to true for case-sensitive filename comparisons, + even on non-case-sensitive platforms such as Windows. + + -2147483646 No revision No revision 1.9.4.1 +2 -0 jakarta-tomcat/src/examples/WEB-INF/web.xml Index: web.xml =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/examples/WEB-INF/web.xml,v retrieving revision 1.9 retrieving revision 1.9.4.1 diff -u -r1.9 -r1.9.4.1 --- web.xml 2000/04/07 22:59:00 1.9 +++ web.xml 2000/12/12 01:01:02 1.9.4.1 @@ -27,6 +27,7 @@ servletToJsp + servletToJsp No revision No revision 1.4.6.1 +3 -1 jakarta-tomcat/src/examples/WEB-INF/classes/examples/ShowSource.java Index: ShowSource.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/examples/WEB-INF/classes/examples/ShowSource.java,v retrieving revision 1.4 retrieving revision 1.4.6.1 diff -u -r1.4 -r1.4.6.1 --- ShowSource.java 2000/03/07 19:53:39 1.4 +++ ShowSource.java 2000/12/12 01:01:03 1.4.6.1 @@ -20,7 +20,9 @@ } public int doEndTag() throws JspException { - if (jspFile.indexOf( ".." ) >= 0) + if ((jspFile.indexOf( ".." ) >= 0) || + (jspFile.toUpperCase().indexOf("/WEB-INF/") != 0) || + (jspFile.toUpperCase().indexOf("/META-INF/") != 0)) throw new JspTagException("Invalid JSP file " + jspFile); InputStream in No revision No revision 1.21.4.1 +1 -1 jakarta-tomcat/src/share/org/apache/jasper/runtime/Attic/JspServlet.java Index: JspServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/runtime/Attic/JspServlet.java,v retrieving revision 1.21 retrieving revision 1.21.4.1 diff -u -r1.21 -r1.21.4.1 --- JspServlet.java 2000/04/05 03:36:42 1.21 +++ JspServlet.java 2000/12/12 01:01:03 1.21.4.1 @@ -178,7 +178,7 @@ response.sendError(HttpServletResponse.SC_NOT_FOUND, Constants.getString("jsp.error.file.not.found", new Object[] { - ex.getMessage() + jspUri })); return; No revision No revision 1.21.4.1 +39 -1 jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp12ConnectionHandler.java Index: Ajp12ConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp12ConnectionHandler.java,v retrieving revision 1.21 retrieving revision 1.21.4.1 diff -u -r1.21 -r1.21.4.1 --- Ajp12ConnectionHandler.java 2000/04/06 23:11:36 1.21 +++ Ajp12ConnectionHandler.java 2000/12/12 01:01:04 1.21.4.1 @@ -354,8 +354,11 @@ } else { try { // close the socket connection before handling any signal + InetAddress serverAddr = socket.getLocalAddress(); + InetAddress clientAddr = socket.getInetAddress(); sin.close(); - if ( signal== 15 ) { + if ( (signal== 15) && + isSameAddress(serverAddr, clientAddr) ) { // Shutdown - probably apache was stoped with apachectl stop contextM.stop(); // same behavior as in past, because it seems that @@ -424,6 +427,41 @@ // XXX // Support persistent connection in AJP21 //moreRequests = false; + } + + /** + * Return true if the specified client and server addresses + * are the same. This method works around a bug in the IBM 1.1.8 JVM on + * Linux, where the address bytes are returned reversed in some + * circumstances. + * + * @param server The server's InetAddress + * @param client The client's InetAddress + */ + private boolean isSameAddress(InetAddress server, InetAddress client) { + + // Compare the byte array versions of the two addresses + byte serverAddr[] = server.getAddress(); + byte clientAddr[] = client.getAddress(); + if (serverAddr.length != clientAddr.length) + return (false); + boolean match = true; + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[i]) { + match = false; + break; + } + } + if (match) + return (true); + + // Compare the reversed form of the two addresses + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i]) + return (false); + } + return (true); + } } No revision No revision 1.13.2.1.2.1 +21 -3 jakarta-tomcat/src/share/org/apache/tomcat/servlets/Attic/DefaultServlet.java Index: DefaultServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/Attic/DefaultServlet.java,v retrieving revision 1.13.2.1 retrieving revision 1.13.2.1.2.1 diff -u -r1.13.2.1 -r1.13.2.1.2.1 --- DefaultServlet.java 2000/04/13 12:46:37 1.13.2.1 +++ DefaultServlet.java 2000/12/12 01:01:05 1.13.2.1.2.1 @@ -82,6 +82,7 @@ private Context context; String docBase; int debug=0; + boolean caseSensitive = true; public void init() throws ServletException { contextF = getServletContext(); @@ -100,6 +101,18 @@ // debug String dbg=getServletConfig().getInitParameter("debug"); if( dbg!=null) debug=1; + + // case sensitivity on Windows + String value = getServletConfig().getInitParameter("caseSensitive"); + if (value != null) { + if ("true".equalsIgnoreCase(value) || + "yes".equalsIgnoreCase(value) || + "on".equalsIgnoreCase(value)) + caseSensitive = true; + else + caseSensitive = false; + } + } public String getServletInfo() { @@ -273,11 +286,16 @@ // So, a check for File.separatorChar='\\' ..... It hopefully // happens on flavors of Windows. if (File.separatorChar == '\\') { - // On Windows check ignore case.... - if(!absPath.equalsIgnoreCase(canPath)) { + // On Windows check case if requested .... + boolean result; + if (caseSensitive) + result = !absPath.equals(canPath); + else + result = !absPath.equalsIgnoreCase(canPath); + if (result) { response.sendError(response.SC_NOT_FOUND); return; - } + } } else { // The following code on Non Windows disallows ../ // in the path but also disallows symlinks.... No revision No revision 1.1.1.1.8.1 +113 -41 jakarta-tomcat/src/share/org/apache/tomcat/util/SessionIdGenerator.java Index: SessionIdGenerator.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/SessionIdGenerator.java,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.1.8.1 diff -u -r1.1.1.1 -r1.1.1.1.8.1 --- SessionIdGenerator.java 1999/10/09 00:20:56 1.1.1.1 +++ SessionIdGenerator.java 2000/12/12 01:01:05 1.1.1.1.8.1 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/SessionIdGenerator.java,v 1.1.1.1 1999/10/09 00:20:56 duncan Exp $ - * $Revision: 1.1.1.1 $ - * $Date: 1999/10/09 00:20:56 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/SessionIdGenerator.java,v 1.1.1.1.8.1 2000/12/12 01:01:05 craigmcc Exp $ + * $Revision: 1.1.1.1.8.1 $ + * $Date: 2000/12/12 01:01:05 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999 The Apache Software Foundation. All rights + * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,7 +15,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -23,15 +23,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * any, must include the following acknowlegement: + * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written + * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" @@ -59,50 +59,122 @@ * * [Additional notices, if required by prior licensing conditions] * - */ + */ package org.apache.tomcat.util; /** - * Generates sesssion ids for the system. The ids produced by this - * class aren't very sophisticated being just a random number followed - * by a synchronized counter. + * This class generates a unique 10+ character id. This is good + * for authenticating users or tracking users around. + *

+ * This code was borrowed from Apache JServ.JServServletManager.java. + * It is what Apache JServ uses to generate session ids for users. + * Unfortunately, it was not included in Apache JServ as a class + * so I had to create one here in order to use it. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jhunter@acm.org] + * @author Jon S. Stevens jon@latchkey.com + * @author Shai Fultheim [shai@brm.com] */ - public class SessionIdGenerator { - private static int counter = 1010; - - public static synchronized String generateId() { - - // XXX - // This code is not very secure at all. It's good enough - // for a reference implementation where you want to make - // sure to not repeat under most circumstances -- but its - // not anything that could be considered to be safe for - // military or banking use. - - // maybe..... - // replace with some sort of MD5 hash so that it is impossible - // to figure out which is the counter and which is the random - - Integer i = new Integer(counter++); - StringBuffer buf = new StringBuffer(); - String dString = Double.toString(Math.abs(Math.random())); - - // we do the substring to get rid of the initial '0.' - // characters. - - buf.append("To"); - buf.append(i); - buf.append("mC"); - buf.append(dString.substring(2, dString.length())); - buf.append("At"); + /* + * Create a suitable string for session identification + * Use synchronized count and time to ensure uniqueness. + * Use random string to ensure timestamp cannot be guessed + * by programmed attack. + * + * format of id is <6 chars random><3 chars time><1+ char count> + */ + static private int session_count = 0; + static private long lastTimeVal = 0; + static private java.util.Random randomSource; + + // MAX_RADIX is 36 + /* + * we want to have a random string with a length of + * 6 characters. Since we encode it BASE 36, we've to + * modulo it with the following value: + */ + public final static long maxRandomLen = 2176782336L; // 36 ** 6 + + /* + * The session identifier must be unique within the typical lifespan + * of a Session, the value can roll over after that. 3 characters: + * (this means a roll over after over an day which is much larger + * than a typical lifespan) + */ + public final static long maxSessionLifespanTics = 46656; // 36 ** 3 + + /* + * millisecons between different tics. So this means that the + * 3-character time string has a new value every 2 seconds: + */ + public final static long ticDifference = 2000; + + // ** NOTE that this must work together with get_jserv_session_balance() + // ** in jserv_balance.c + static synchronized public String getIdentifier (String jsIdent) + { + StringBuffer sessionId = new StringBuffer(); + + if (randomSource == null) { + String className = System.getProperty("tomcat.sessionid.randomclass"); + if (className != null) { + try { + Class randomClass = Class.forName(className); + randomSource = (java.util.Random)randomClass.newInstance(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + if (randomSource == null) + randomSource = new java.security.SecureRandom(); + } + + // random value .. + long n = randomSource.nextLong(); + if (n < 0) n = -n; + n %= maxRandomLen; + // add maxLen to pad the leading characters with '0'; remove + // first digit with substring. + n += maxRandomLen; + sessionId.append (Long.toString(n, Character.MAX_RADIX) + .substring(1)); + + long timeVal = (System.currentTimeMillis() / ticDifference); + // cut.. + timeVal %= maxSessionLifespanTics; + // padding, see above + timeVal += maxSessionLifespanTics; + + sessionId.append (Long.toString (timeVal, Character.MAX_RADIX) + .substring(1)); + + /* + * make the string unique: append the session count since last + * time flip. + */ + // count sessions only within tics. So the 'real' session count + // isn't exposed to the public .. + if (lastTimeVal != timeVal) { + lastTimeVal = timeVal; + session_count = 0; + } + sessionId.append (Long.toString (++session_count, + Character.MAX_RADIX)); + + if (jsIdent != null && jsIdent.length() > 0) { + return sessionId.toString()+"."+jsIdent; + } + return sessionId.toString(); + } - return buf.toString(); + public static synchronized String generateId(String jsIdent) { + return getIdentifier(jsIdent); } + } 1.3.4.1 +5 -24 jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/SessionUtil.java Index: SessionUtil.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/SessionUtil.java,v retrieving revision 1.3 retrieving revision 1.3.4.1 diff -u -r1.3 -r1.3.4.1 --- SessionUtil.java 2000/02/14 04:59:43 1.3 +++ SessionUtil.java 2000/12/12 01:01:06 1.3.4.1 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/SessionUtil.java,v 1.3 2000/02/14 04:59:43 costin Exp $ - * $Revision: 1.3 $ - * $Date: 2000/02/14 04:59:43 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Attic/SessionUtil.java,v 1.3.4.1 2000/12/12 01:01:06 craigmcc Exp $ + * $Revision: 1.3.4.1 $ + * $Date: 2000/12/12 01:01:06 $ * * ==================================================================== * @@ -75,21 +75,12 @@ * Session implementations. * * @author Craig R. McClanahan - * @version $Revision: 1.3 $ $Date: 2000/02/14 04:59:43 $ + * @version $Revision: 1.3.4.1 $ $Date: 2000/12/12 01:01:06 $ */ public final class SessionUtil { - // ------------------------------------------------------- Static Variables - - - /** - * Private counter used in generating session identifiers. - */ - private static int counter = 1010; - - // --------------------------------------------------------- Public Methods @@ -182,18 +173,8 @@ * is not at all sophisticated or secure. */ public static String generateSessionId() { - - Integer i = new Integer(counter++); - StringBuffer buf = new StringBuffer(); - String dString = Double.toString(Math.abs(Math.random())); - - buf.append("To"); - buf.append(i); - buf.append("mC"); - buf.append(dString.substring(2)); // Skip "0." at the start - buf.append("At"); - return (buf.toString()); + return (SessionIdGenerator.generateId(null)); }