Hardening Tomcat 6.x: Security Configuration, File Permissions, and Apache Integration Best Practices


7 views

When deploying Tomcat 6.x on Debian Lenny, the first step is proper filesystem isolation. Create a dedicated system user with minimal privileges:

# Create jakarta user with no login shell
sudo useradd -r -s /bin/false jakarta

Set strict directory permissions (adjust paths based on your installation):

sudo chown -R jakarta:jakarta /opt/tomcat
sudo chmod -R 750 /opt/tomcat
sudo chmod 750 /opt/tomcat/conf
sudo chmod 640 /opt/tomcat/conf/*

Delete all sample applications that ship with Tomcat:

rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
rm -rf /opt/tomcat/webapps/manager
rm -rf /opt/tomcat/webapps/host-manager

For production deployments, consider removing the ROOT webapp as well and deploying your application as the root context.

Key configuration changes in server.xml:

<Connector port="8080" protocol="HTTP/1.1"
    address="127.0.0.1"
    maxThreads="150"
    minSpareThreads="25"
    enableLookups="false"
    acceptCount="100"
    disableUploadTimeout="true"/>

In web.xml, add these security constraints:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Restricted Methods</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
        <http-method>OPTIONS</http-method>
        <http-method>TRACE</http-method>
    </web-resource-collection>
    <auth-constraint/>
</security-constraint>

Enabling the Security Manager adds significant protection. Add to catalina.sh:

export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.manager -Djava.security.policy==$CATALINA_BASE/conf/catalina.policy"

Example policy file entries:

// Basic permissions for all webapps
grant {
    permission java.util.PropertyPermission "java.version", "read";
    permission java.util.PropertyPermission "java.vendor", "read";
    permission java.util.PropertyPermission "java.class.version", "read";
};

// Specific permissions for your application
grant codeBase "file:${catalina.base}/webapps/your-app/-" {
    permission java.io.FilePermission "${catalina.base}/webapps/your-app/-", "read,write";
    permission java.net.SocketPermission "db.yourdomain.com:3306", "connect";
};

For production deployments, running Tomcat behind Apache with mod_jk is recommended over mod_proxy for better performance and control. Example workers.properties:

worker.list=loadbalancer
worker.node1.port=8009
worker.node1.host=localhost
worker.node1.type=ajp13
worker.node1.lbfactor=1
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1

In httpd.conf:

LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
JkMount /* loadbalancer
  • Implement regular log monitoring for suspicious activity
  • Set up HTTPS using APR or a reverse proxy
  • Regularly apply security patches (consider upgrading to a supported Tomcat version)
  • Implement fail2ban for repeated failed login attempts
  • Disable server signature in HTTP headers

Running Tomcat as a non-root user (like your 'jakarta' user) is a great first step. Here's how to properly configure permissions:

# Directory structure recommendation
chown -R jakarta:jakarta /opt/tomcat
chmod -R 750 /opt/tomcat
find /opt/tomcat/conf -type f -exec chmod 640 {} \;
find /opt/tomcat/bin -type f -name "*.sh" -exec chmod 750 {} \;

All default webapps should be removed as they contain vulnerabilities:

rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
rm -rf /opt/tomcat/webapps/manager
rm -rf /opt/tomcat/webapps/host-manager

Key modifications needed in server.xml:

<Connector port="8080" protocol="HTTP/1.1"
           address="127.0.0.1"
           maxHttpHeaderSize="8192"
           maxThreads="150"
           minSpareThreads="25"
           enableLookups="false"
           acceptCount="100"
           disableUploadTimeout="true" />

Enabling the Security Manager adds an important layer of protection. Add this to catalina.sh:

JAVA_OPTS="$JAVA_OPTS -Djava.security.manager -Djava.security.policy==$CATALINA_BASE/conf/catalina.policy"

Sample policy file entries:

// Required permissions
grant codeBase "file:${catalina.home}/bin/-" {
    permission java.security.AllPermission;
};

// Web application permissions (restrictive)
grant codeBase "file:${catalina.home}/webapps/your-app/-" {
    permission java.io.FilePermission "${catalina.home}/webapps/your-app/-", "read,write";
    permission java.lang.RuntimePermission "getClassLoader";
};

Using mod_proxy is simpler than mod_jk for most cases. Example configuration:

<VirtualHost *:80>
    ServerName yourdomain.com
    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/
    ProxyPreserveHost On
    <Proxy *>
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Proxy>
</VirtualHost>
  • Set secure and httpOnly flags for cookies in context.xml
  • Disable TRACE and OPTIONS methods in web.xml
  • Implement CSRF protection for web applications
  • Regularly update Java and Tomcat with security patches

Example web.xml configuration for disabling TRACE:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Disable TRACE</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>TRACE</http-method>
    </web-resource-collection>
    <auth-constraint />
</security-constraint>