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 29550 invoked from network); 6 Nov 1999 22:54:19 -0000 Received: from naturesowndistributor.com (HELO gefionsoftware.com) (gefion@209.210.26.56) by apache.org with SMTP; 6 Nov 1999 22:54:19 -0000 Received: from gefionsoftware.com (1Cust155.tnt3.redondo-beach.ca.da.uu.net [63.25.35.155]) by gefionsoftware.com (8.8.8/8.7.1) with ESMTP id XAA22506 for ; Sat, 6 Nov 1999 23:02:38 GMT Message-ID: <3824B149.D97EAE66@gefionsoftware.com> Date: Sat, 06 Nov 1999 14:52:57 -0800 From: Hans Bergsten Organization: Gefion software X-Mailer: Mozilla 4.5 [en] (WinNT; I) X-Accept-Language: en MIME-Version: 1.0 To: tomcat-dev@jakarta.apache.org Subject: DefaultServlet path checks References: <19991028010424.25960.qmail@hyperreal.org> <3823A050.C8FCAD9D@gefionsoftware.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit I believe I've found a solution for checking the path in the DefaultServlet that works with both 8.3 and long file paths on Windows and symbolic links on Unix, and still catches all attempts to get to the source of JSP files or other extension mapped files. I have only tested this on Windows but I don't see why it shouldn't work on other platforms. The solution is to always check for ".." and then only compare the file extension part of the URI with with the file extension from the canonical path. As far as I can tell, that's the only part we need to worry about since that's where extra characters or mixed case can fool the container to dispatch to DefaultServlet instead of a servlet mapped to the file extension. Mixed case in the path itself doesn't really matter; on a case sensitive platform the file will not be found, on a case insensitive it will be found but that's okay as long as we catch tricks with the extension part. Please take a look at this version of the serveFile() method. If everyone is happy with it, I will commit it to both the J2EE branch and the main branch. private void serveFile(File file, HttpServletRequest request, HttpServletResponse response) throws IOException { String absPath = file.getAbsolutePath(); String canPath = file.getCanonicalPath(); if(absPath.indexOf("..") != -1) { // We have .. in the path... response.sendError(response.SC_NOT_FOUND, "File Not Found:
" + absPath); return; } // Compare the file extension part of the requested name // with the "real" extension, to catch attempts to read // shtml or jsp source by adding characters or using mixed // case extension on Windows platforms String reqExt = absPath; int dot = absPath.lastIndexOf('.'); if (dot != -1 && dot < absPath.length() - 1) { reqExt = absPath.substring(dot + 1); } String canExt = canPath; dot = canPath.lastIndexOf('.'); if (dot != -1 && dot < canPath.length() - 1) { canExt = canPath.substring(dot + 1); } if (!canExt.equals(reqExt)) { response.sendError(response.SC_NOT_FOUND, "File Not Found:
" + absPath); return; } String mimeType = mimeTypes.getContentTypeFor(file.getName()); if (mimeType == null) { mimeType = "text/plain"; } response.setContentType(mimeType); response.setContentLength((int)file.length()); response.setDateHeader("Last-Modified", file.lastModified()); FileInputStream in = new FileInputStream(file); try { serveStream(in, request, response); } catch (FileNotFoundException e) { // Figure out what we're serving String requestURI = (String)request.getAttribute( Constants.Attribute.RequestURI); if (requestURI == null) { requestURI = request.getRequestURI(); } response.sendError(response.SC_NOT_FOUND, "File Not Found
" + requestURI); } catch (SocketException e) { return; // munch } finally { if (in != null) { in.close(); } } } -- Hans Bergsten hans@gefionsoftware.com Gefion Software http://www.gefionsoftware.com