Search code examples
javatomcatembedded-tomcat

Are there security concerns with embedded Tomcat's Context.docBase?


When creating a org.apache.catalina.Context, you need to specify a "docBase" argument. docBase is supposed to be an existing directory. Context creation fails if it's not an existing, accessible directory.

The java doc describes this parameter as "Base directory for the context, for static files. Must exist, relative to the server home". What does Tomcat do with that directory? Will it potentially serve files from that location? What is the safest value for that argument, if I don't want to serve static files?

For example, in the simplest embedded Tomcat server I could write, is there the possibility that the File(".").getAbsolutePath() argument could be used by a malicious client to retrieve files from the current directory?

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

/**
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.56</version>
        </dependency>
 */
public class OneServlet {
    public static void main(String[] args) {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(9000);
        tomcat.getConnector();

        var context = tomcat.addContext("", new File(".").getAbsolutePath());
        Tomcat.addServlet(context, "servlet", new HttpServlet() {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                resp.getWriter().write("Hello world");
            }
        });
        context.addServletMappingDecoded("/", "servlet");

        try {
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }
}

Solution

  • In a traditional deployment docBase points to the root of your WAR file or to the directory with the expanded WAR file. It is the base URL against which ServletContext#getResource calls are resolved and also the root for the DefaultServlet.

    In your case using new File(".").getAbsoluteFile() would indeed allow an attacker to retrieve all files, assuming they can guess their names and the request is not intercepted by one of your servlets. It does not happen, because you call Tomcat#addContext instead of Tomcat#addWebapp, which prevents Tomcat from applying a default web.xml to your application (i.e. no DefaultServlet).

    However, a safer bet would be to use null as docBase. On modern Tomcat's this will cause the creation of an empty in-memory resource set (cf. source code).