Tomcat Security

I am only going to discuss Tomcat security and not any Unix/Windows security I leave you to investigate that area, there are many operating system security documents on the internet. I advise you to also check the Tomcat web site for the very latest security issues as security is changing all the time and vulnerabilities on Tomcat will be reported here as soon as they are discovered.

Most software downloaded can be checked that it has not been tampered with or that you are downloading the correct version and not a hacked version. Tomcat uses a MD5 digest to make sure that you have downloaded the correct version, if one bit was to change in the software the MD5 digest will change. So when you have downloaded Tomcat, don't forget to compare the MD5 digest with the official Tomcat website to check it's integrity.

Securing Tomcat

When moving Tomcat into Production a number of actions must be performed to secure Tomcat, these are recommendations and you can choose to implement or not implement them. To start with I will discuss securing the Tomcat instance then discuss securing the Web application

Securing the Tomcat Instance
Remove default applications

By default Tomcat ships with a number of Web applications which are installed and ready to run

  • ROOT: contains the simple default welcome page
  • docs: Tomcat documentation
  • examples: Simple examples of JSPs and servlets demonstrating Tomcat
  • manager and host-manager: Two powerful system applications to make administrating virtual hosts and the Tomcat servers more convenient

These all should be removed from a Production environment, manager and host-manager present the greatest security risk.

Changing the shutdown command

By default Tomcat can be shutdown by connecting to Tomcat on port 8005 (default) and sending the following character sequence

SHUTDOWN

You might want to change the character sequence and port number

<server port="8098" shutdown="goingdown">

Run Tomcat under its own account Many applications require this, by using its own user account it has less operating system privileges. The startup scripts can "su" to the Tomcat account to start Tomcat.
Securing the Filesystem This is standard operating system stuff, by using a Tomcat account and making sure the file permissions are set correctly you reduce the risk that if Tomcat is compromised the whole server is still secure.
Securing the JVM By using a policy file you can restrict what classes are accessed, this file can be very fine grained.

Securing JVM

I mentioned above securing the JVM, here I go into more detail. By default the security mechanism is turned off, but it can be turned on at any time

Enable the security manager via java command

$java -Djava.security.manager MyClass

Note: in Tomcat's run.sh script you can add the "java.security.manager" to the JAVA_OPTS variable

Enabling the security manager in Tomcat $ catalina.sh start -security

The security manager architecture is based on the concept of permissions, once the security is turned on, the application must have explicit permissions to perform certain security-sensitive tasks (such as creating a custom class loader, opening a network socket). Policy files are used by the security manager to grant permissions to applications, they are simple text files composed of individual actions that applications are allowed to perform.

They are posed of grants like below

grant syntax

grant codeBase "URL" {
  // this is a common
  permission permission_class_name "target_name", "action";
  ...
};

policy file example

grant {
  permissions java.lang.RuntimePermissions "stopThread";
}

grant codeBase "file:${java.home}/lib/ext/*" {
  permissions java.security.AllPermission;
}
 
Note: the first grant grants all applications the capability to access the deprecated Thread.stop() method

The second grant grants code in a specific location to use all other code, which effectively disables the security manager for that code  

You can of course use more than one permission within a grant block, below is a list of the common permissions that you can grant

Target Name Description
createClassLoader Allows an application to create a custom class loader
exitVM.{n} Allows an application to exit the JVM via the System.exit(n) method
java.security.AllPermissions All other permissions are granted, same as disabling the security manager
java.security.SecurityPermissions Allows programmatic access to various security features of the Java programming language
java.security.UnresolvedPermission Used as a placeholder when a policy file makes reference to a user defined permission class that had not been loaded at the time of processing the policy file
java.awt.AWTPermission Controls various AWT permissions
java.io.FilePermission Restricts read, write, execute and delete access to files
java.io.SerializablePermission Allows serialization permissions
java.lang.reflect.ReflectPermission Allows applications to circumvent the public and private mechanisms access checks and reflectively access any method
java.lang.RuntimePermission Allows access to key runtime features (creating class loaders, exiting the JVM and reassigning STDIN, STDOUT and STDERR
java.net.NetPermission Allow various network permissions
java.net.SocketPermission Allows incoming socket connections, outgoing connections, listening on ports and resolving hostnames.
java.sql.SQLPermission Controls the setting of the JDBC log output writer
java.util.PropertyPermission Controls whether properties can be read from and written to
java.util.logging.LoggingPermission Allow the capability to configure the logging system
javax.net.ssl.SSLPermission Allows the capability to access SSL-related network functionality
javax.security.auth.AuthPermission Controls authentication permissions
javax.security.auth. and PrivateCredentialPermission Controls various security permissions
javax.security.auth.kerberos. and DelegationPermission Controls various security permissions related to the Kerberos protocol
javax.security.auth.kerberos. and ServicePermission Controls various security permissions related to the Kerberos protocol
javax.sound.sampled.AudioPermission Controls access to the sound system

Tomcat's Policy File

Tomcat uses the catalina.policy file in the conf directory to determine its own permissions and those of its Web applications. The file is broken into three sections

Securing Web Applications

There are a number of ways to secure the Web applications, by using the following techniques

All the above techniques can be applied by modifying the XML configuration files of the Web application typically the web.xml file.

Authentication is the process of determining and validating the identify of an application client, the Servlet specification provides integration with the Java Authentication and Authorization Service (JAAS) API. Tomcat uses Realms to implement user authentication, Realms hold authentication data that can be accessed via programmatic security or via declarative security (config files).

Servlet-based applications have four authentication mechanisms to choose from

BASIC The BASIC authentication mechanism is simplistic, it has some serious problems as it uses Base64 which is not very secure and the browser caches credentials after authentication.
DIGEST DIGEST is the next set up, it is the same as BASIC but the password is transmitted in a secure fashion, it performs a digest on the password (one way hash) before sending it across the wire. It to has flaws the original password must be stored somewhere in plain text and it to suffers from the same browser caching problem. DIGEST can use either MD5 or SHA to hash the password.
Form The browser does not help with the authentication, instead it creates a HTML form where the username and password is entered and passed to the servlet container, this can be secured by using HTTPS. However it has one flaw where the username and password must be stored somewhere on the servlet container, normally in plain text.
HTTPS Client Certificate When the browser establishes a connection, the browser is sent a public key certificate from the server, this certificate enables the browser to authenticate with the server. This enables the browser to know the true identity of the server as certified(signed) by a trusted third party (such as VeriSign). This is the most secure method but it too has flaw, if the key length used to encrypt the messages is to short then it becomes more vulnerable to attacks, also the theft of the private key would result in the authentication becoming compromised.

Now for an example

Configuring Authentication <web-app ...>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Entire Application</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>
  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>My Test Application</realm-name>
    <form-login-config>
      <form-login-page>/login.jsp</form-login-page>
      <form-error-page>/error.jsp</form-error-page>
    </form-login-config>
  </login-config>
  ...
  <security-role>
    <role-name>manager</role-name>
  </security-role>
</web-app>
  
Authentication Form <html>
  <head><title>Please login</title>
  <body>
    <form method="POST" action="<%= response.encodeURL("j_security_check")%>">
      <table>
      <tr>
        <th>Username:</th>
        <td><input type="text" name="j_username"></td>
      </tr>
      <tr>
        <th>Password:</th>
        <td><input type="text" name="j_password"></td>
      </tr>
      <tr>
        <td><input type="submit" value="Log In"></td>
        <td><input type="reset"></td>
      </tr>
      </table>
    </form>
  </body>
</html> 
tomcat-users.xml <tomcat-users>
  <role rolename="guest"/>
  <role rolename="manager"/>
  <user username="vallep" password="secret" roles="manager,guest" />
  ...
</tomcat-users>

I have also touched on web application security in my JSP feature.

Security Realms

Tomcat uses Realms which store the credentials that are used to authenticate the client. A Realm is a standard programming interface defined in Tomcat for accessing a users username, password and roles. Just to recap you can only have one Realm in each of the following <Engine>, <Host> and <Context> elements, see Tomcat Architecture for more details.

Tomcat uses the concept of users and roles, users are assigned to a role and a role is given the permission to access resources. This concept is not new and is used in many other software applications. Because Tomcat separates the users and roles they can be dynamically changed without restarting the instance. Tomcat can use four built-in Realms

File-based Realm maintains its authentication data in flat files, this file can be edited by a normal text editor. The file is in human readable text and the primary built-in file-based Realm is called the UserDatabase.

UserDatabase reads the file when Tomcat is started and then uses memory to access the data, it has the following properties

Configuring the UserDatabase (server.xml)

<GlobalNamingResources>
  <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users
  -->
  <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"
            description="User database that can be updated and saved"
            factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
            pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>

Note: this Realm can now be accessed via JNDI

Make the UserDatabase accessible

<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>

Note: this would be placed in the <engine> container level

Using DIGEST algorithm

-- You can secure the above method more by using DIGEST instead of BASIC method

<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" digest="sha"/>

-- create the DIGEST password for the user
# $CATALINA_HOME/bin/digest -a sha <password>
<password>:<DIGEST>

-- Now use the output <DIGEST> command into the tomcat-users.xml file

<user username="pvalle" password="<DIGEST>"

JDBC Realms are basically the same as a file-based Realm but you instead use a RDMS to hold the authentication data. I am not going to go into to much detail here as I have already covered JDBC connections.

A JDBC Realm can use a number of attributes

JDBC Realm Component Attributes
Attribute Description
className The Java class that the Server uses by default it uses org.apache.catalina.realm.JDBCRealm
connectionName The JDBC connection username to be used
connectionPassword The JDBC connection password to be used
connectionURL The JDBC URL to be used to access the database
digest Specifies the digest algorithm to be used
driverName Name of the JDBC driver
userTable The actual name of the table in the database that matches the Users table in the required view.
userNameCol The actual column name of the column in both the Usertable and UserRoleTable that matches the User column in the required view
userCredCol The actual column name of the column in the Usertable that matches the Password column in the required view
userRoleTable The actual name of the table in the database that matches the user_roles table in the required view
roleNameCol The name of the column in the userRoleTable that matches the role_name column in the required view
Example
MySQL example

<Realm className="org.apache.catalina.realm.JDBCRealm"
           driverName="com.mysql.jdbc.Driver"
           connectionURL="jdbc:mysql://localhost/authority"
           connectionName="Tomcat" connectionPassword="password"
           userTable="users" userNameCol="login" userCredCol="password"
           userRoleTable="user_roles" roleNameCol="role"
           digest="md5"
/>

Note: don't forgot to comment out any other Realm

JNDI Realms (I have already discussed JNDI) store authentication data in a LDAP (Lightweight Directory Access Protocol) directory server and accesses it using JNDI. I will leave you to investigate how to set this up but will give you the attributes that are used

JNDI Realm Component Attributes
Attribute Description
className

The Java class that the Server uses by default it uses org.apache.catalina.realm.JNDIRealm

connectionName The username used to authenticate against the directory service via JNDI
connectionPassword The password used to authenticate against the directory service via JNDI
connectionURL The URL to locate the directory service
contextFactory Configures the Java programming language class used to create the a context for the JNDI connection
Digest Specifies the digest algorithm to be used
userPassword Maps the name of the directory attribute from the user element that contains the password information
userPattern Specifies an LDAP pattern for searching the directory for selecting user entry
roleName Maps the name of the directory attribute that contains the role name
roleSearch Specifies an LDAP pattern for searching the directory for selecting roles entry
roleBase Specifies the base element for the role searches
roleSubtree If set to true a subtree search will be conducted for the role, (default false).

JAAS Realms uses the Java Authentication and Authorization Service (JAAS) to authenticate a user to provide access control. Again I will leave you to investigate how to set this up but will give you the attributes that are used

JAAS Realm Component Attributes
Attribute Description
className

The Java class that the Server uses by default it uses org.apache.catalina.realm.JAASRealm

debug The debug level (0 means off)
appName The application name passed to the JAAS loginContext which uses it to select the set of relevant LoginModules
roleClassNames Comma-delimited list of javax.security.Principlal classes that represent security roles
userClassNames Comma-delimited list of javax.security.Principlal classes that represent security roles
Example
  <Realm className="org-apache.catalina.realm.JAASRealm"
       appName="Tomcat"
       roleClassNames="uk.co.datadisk.APrincipalImpl"
       userClassNames="uk.co.datadisk.AnotherPrincipalImpl"
/>

There are five steps in configuring a JAAS Realm

  1. Perform the setup required for the actual authentication technology (i.e setup JNDI)
  2. Write or obtain a Provider for the authentication technology
  3. Configure the Provider
  4. Make changes to the Java Security Policy
  5. Configure the Realm directive

Encryption with SSL

Secure Sockets Layer (SSL) is a protocol that enables secure communication between clients and servers in a network environment. A pair of encryption keys are used (public key and private key) to encrypt/decrypt the messages, you encrypt the message with the public key and only the private can decrypt it. When a client opens an SSL connection with a server an SSL handshake is performed

  1. The server sends a digital certificate to the client, this contains the public key of the server and other information
  2. The client then authenticates the server based on the certificate and the trustworthiness of the authority that issued the certificate (VeriSign). The user is warned if the certificate is not verified
  3. A session key is then generated and encrypted with the public key and exchanged over the connection. The session key is then used for the duration of the session to encrypt all subsequent data transmissions.

In order to use SSL you must have the SSL or TLS package downloaded and installed.

You can protect resources using SSL and there are three levels of integrity

using SSL <security-constraint>
  ...
  <user-data-constraint>
    <description>Constrain the user data transport for the whole application</description>
    <transport-guarantee>CONFIDENTAL</transport-guarantee>
  </user-data-constraint>
</security-constraint>

Tomcat has a HTTPS connector already setup, you just need to uncomment it

Tomcat SSL connector <Connector
   port="8443"
   scheme="https"
   secure="true"
   SSLEnabled="true"
   keystoreFile="${user.home}/.keystore"
   clientAuth="false"
   sslProtocol="TLS"
/>

Securing DefaultServlet

Tomcat uses the DefaultServlet to serve any static web page that does not map to a servlet, this is configured in conf/web.xml. If the resource is not found Tomcat could display a file directory listing instead which is a security risk, by default is this disabled but you will want to make sure.

enable/disable directory listings

<servlet>
  <servlet-name>default</servlet-name>
  <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
  <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
  </init-param>
  <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>

   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>

Note: the text in bold is what enables/disables directory listing

Host Restriction

I have already discuss host restriction.