Securing your Tomcat server is critical if you are ever to serve live Web applications. Even if you only run your Tomcat server as a test server, the following concepts are important to understand and implement.
Think about security from two different perspectives: server security and application security. Server security includes the Java Security Manager, starting Tomcat under a secure port, and setting up SSL certificates for the server. Application security relates mainly to authentication and authorization of users based on security roles, depending on the protected asset they're trying to access.
SSL setup on the Tomcat server is highly recommended if you're using the server as a stand-alone server. If you have a front-end HTTP server, that server will likely be handling all SSL over HTTP (HTTPS) connections in which SSL is required and routing those requests to the appropriate Tomcat server. In other circumstances, Tomcat servers may need SSL turned on even if they are behind the same firewall in the same network to initiate trusted connections between themselves.
SSL connectivity is in essence two servers that trust each other communicating with each other. The way they trust each other is by having security keys that are either self-signed or verified by a third party.
Self-signed certificates are fine for encryption but not acceptable for true online trusted authentication. You will see many warning messages in your browser when attempting to access a site with only a self-signed certificate.
The process for storing, requesting, and importing signed server certificates is discussed below. This information is a prerequisite to performing even the most basic Tomcat security maneuvers, like starting the server under a secure port.
Fortunately, Java provides a relatively simple command-line tool called
keytool that can easily create a self-signed
certificate. Self-signed certificates are simply user-generated certificates
that have not been officially registered with any well-known certification
authority (CA) and are therefore not really guaranteed to be authentic at
all. However, with
keytool, you can generate
a certificate request that can be sent to a third party for trusted verification
and sent back "signed" so that you can again use
to import that signed server certificate. Then, when clients or other servers
access your server or application, they will know your server is who it says
Before you obtain your security certificates, you must have a place to put them. This place is called your keystore. You can also create your self-signed certificate at the same time using the command shown in Listing 8 or Listing 9, depending on your Java version.
Listing 8. Create your keystore and self-signed certificate for Java version 1.6 or later
keytool -genkeypair -alias tomcat -keyalg RSA -keystore / $CATALINA_HOME/ssl/keystore
Listing 9. Create your keystore and self-signed certificate for Java versions earlier than 1.6
<!-- For Java versions earlier than 1.6, you must run two separate commands. --> keytool -genkey -alias tomcat -keyalg RSA -keystore / $CATALINA_HOME/ssl/keystore <!-- and --> keytool -selfcert -alias tomcat -keystore / $CATALINA_HOME/ssl/keystore
You can specify key size, validity, e-mail address, and so on from the command
line when creating the key, or you can type each value as you are prompted.
Specify a password value of
changeit, which is
the default password recommended by most documentation. Feel free to set
this to something different, if you'd like.
Note: $CATALINA_HOME/ssl is a directory that I created and recommend creating to hold your keystore and server certificates. However, you can include any directory path here as long as you stay consistent when referencing it in the future.
You can edit your keystore at a later time, if needed. When you're prompted
to type your key password for
or whatever your alias name is, press Enter to leave this the same as
your keystore password. You will use your alias to reference your keystore
from here on out.
Listing 10 shows the code for editing your keystore
Listing 10. Edit your keystore
keytool -genkey -alias tomcat -keyalg RSA -keystore / $CATALINA_HOME/ssl/keystore
Change the company, location, default password information, and so on as appropriate.
To obtain a certificate from the CA of your choice, you must first create a Certificate Signing Request (CSR). This is synonymous with Server Cert Request, if you're familiar with that term from working on other software platforms. Listing 11 shows the code for creating a CSR.
Listing 11. Create your CSR
$keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr / -keystore $CATALINA_HOME/ssl/keystore
Now you have a file called certreq.csr that you can submit to the CA. In return, you get a certificate. For a list of third-party digital CAs, see Resources.
To complete the certificate process, perform the following steps:
- Go to your third-party vendor's Web site, and obtain the Root
certificate or certificate chain.
Note that some secure servers require an intermediary and Root certificate. You must obtain both from the third-party vendor, both of which will be in the chain. You can also import these certificates individually.
- Import the chain by typing:
keytool -import -alias root -keystore $CATALINA_HOME/ssl/keystore -trustcacerts -file
where file is the name of the certificate chain.
- Import your signed server certificate by typing:
keytool -import -alias tomcat -keystore $CATALINA_HOME/ssl/keystore -file
where file is the name of your signed certificate file.
You now have the SSL keys necessary to run Tomcat as a trusted server. However, you must now configure Tomcat to use SSL. Tomcat does this through connectors, which the next section defines as you start the server under a secure port.
By default, the server.xml file contains SSL connector information that you
need to "uncomment" to finish configuring Tomcat security. First, make sure
SSLEngine attribute is set to On in the
server.xml file—for example:
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
Listing 12 shows the defaults for the
element in Tomcat version 6's server.xml file.
Listing 12. Connector element defaults:
<Connector port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="$CATALINA_HOME/ssl/keystore" keystorePass="changeit" clientAuth="false" sslProtocol="TLS"/> ...
<Connector> tag, then set
attributes to match what you configured the keystore for. The default
port attribute value used in this example is
8443. This is the TCP/IP port number on which Tomcat will listen for
secure connections. You can change this value to any port number you wish.
Best practice, however, is to stick to somewhat typical SSL ports, such as
Note that if you change the port number here, you should also change the
value specified for the
on the non-SSL connector. This allows Tomcat to automatically redirect
users who attempt to access a secure page or resource specifying that SSL
To access your new protected and secure Tomcat server default page, type the
https://localhost:8443 in your Web
browser's address bar. You should see a page similar to Figure
Figure 2. The Security console Welcome page
A final nugget of truth to keep in your head for later is, if and when you run
secure virtual hosts, you need to add an SSL
element to the SSL connector for each server's keystore.
The built-in Java Security Manager for Tomcat is simply an alternative to protect your Tomcat server from mischievous or accidental code packages that can cause damage to your server. The JRE lets you purposely restrict certain pieces of code from administering the JVM, having certain permissions on your server file systems, and so on. In many cases, a server hosted in an environment easily accessible from the Web should add this additional layer of security so that hackers cannot manipulate the server or view any files on it. Note, however, that this addition can also be too restrictive if your code needs to write files to your server file system for some reason, so use it wisely and test full application functionality before implementing it in a production environment.
The security policies that Security Manager implements are configured in the $CATALINA_HOME/conf/catalina.policy file, with the appropriate permissions pertaining to different pieces of the Web application. Please review the file to determine what and where you will need to edit to change anything that deviates from the default values.
To start the server with Security Manager policies enabled, type the following command:
$CATALINA_HOME/bin/catalina.sh start -security
Securing the server with SSL keys to make it trusted is great, but now you need to make your application (or at least parts of it) prompt users to securely authenticate to gain access to protected resources. Tomcat provides four common authentication mechanisms and also allows for customized secure authentication. For time purposes, I show you how to set up Basic authentication, and then how to expand this to Form-based, Custom, and Digest authentication.
If you configure Basic authentication, users are prompted with a login dialog box when they attempt to access a protected resource. If you use Form-based authentication, users are redirected to an HTML page that allows them to log in when they attempt to access a protected resource. You use Custom authentication when you require additional information from the user before allowing him or her to log in. And you use Digest authentication when you need an added level of security through hashed passwords.
First, define the apps-appname.xml file to specify the application that's going to use Basic authentication as well as the users file that it will reference specifically for security roles for this application. Listing 13 shows the contents of this XML file.
Listing 13. Contents of a conf/apps-appname.xml file
<?xml version="1.0" encoding="ISO-8859-1"?> <webapps> <Context path="/sample" docBase="webapps/sample" reloadable="true"> <SimpleRealm filename="conf/users/appname-users.xml" /> </Context> </webapps>
Next, you must create the application-specific security role in the appname-users.xml file. Type any user name and password you would like, and make sure you give them the appropriate authentication role. For more information on the available roles, refer to the Tomcat documentation (see Resources).
Listing 14 shows an example appname-users.xml file.
Listing 14. Sample conf/users/appname-users.xml
<tomcat-users> <user name="username" password="passwd" roles="rolename" /> </tomcat-users>
Finally, type the details shown in Listing 15 in the main WEB-INF/web.xml file. These details specify your different protected resources and which HTTP methods they are protected against. If you have resources other than JSP or HTML files that you need to protect, you can add them here. Additionally, you will see Basic authentication defined along with which role is given by default to any user on the system.
Listing 15. Sample webapps/appname/WEB-INF/web.xml file
<security-constraint> <web-resource-collection> <web-resource-name>user-resource</web-resource-name> <description>pages which require login</description> <url-pattern>*.jsp</url-pattern> <url-pattern>*.html</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <description>Must authenticate before querying the system</description> <role-name>rolename</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>default</realm-name> </login-config> <security-role> <description>Any user of the system</description> <role-name>rolename</role-name> </security-role>
Note that you will have to ensure that the
section points to the roles in which you created the users.
Form-based authentication is probably the most common way to authenticate users to access-protected Web pages. It has been around for quite a while and allows you to create custom login and error pages to match the look and feel of your site while building upon the security features of Basic authentication.
Form-based authentication when switching back and forth between HTTPS and HTTP is better than Basic authentication, as your user name and password are not sent with each request. Remember that it is still highly recommended that you use a secure transport mechanism such as HTTPS when using Form-based or any of the four authentication mechanisms mentioned here.
To build on the Basic authentication that you've already set up, perform the following steps:
- Create a custom error and login.jsp file (not covered in this tutorial).
- Replace the
login-configsection of the Basic authentication code with the code in Listing 16.
Listing 16. Modify the Basic authentication code
<login-config> <auth-method>FORM</auth-method> <realm-name>Web Demo</realm-name> <form-login-config> <form-login-page>/admin/login.jsp</form-login-page> <form-error-page>/admin/error.jsp</form-error-page> </form-login-config> </login-config>
The security constraint information stays the same.
Note: When creating the HTML form, the following syntax is required:
<form method="POST" action="j_security_check"> <input type="text" name="j_username"> <input type="text" name="j_password"> <input type="submit" value="Log in"> </form>
- Restart Tomcat for the changes to take effect.
Both Form-based and Custom authentication concepts are beyond the scope of this tutorial and require additional development. Custom authentication would have you protect a resource—for example, a JSP file—then refer to that resource in the Web-INF directory, as shown in Listing 17.
Listing 17. Referring to a resource in the WEB-INF/web.xml file
<web-app> <security-constraint> <!-- web resources that are protected --> <web-resource-collection> <web-resource-name>A Protected Page</web-resource-name> <url-pattern>/protected-page.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>resin-user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>Basic Authentication Example</realm-name> <!-- The authenticator tag is Resin-specific --> <authenticator id='beans.SimpleAuthenticator'/> </login-config> </web-app>
Digest authentication is essentially the same as Basic authentication, except that Digest authentication transmits a password's hash value, not the password itself. Listing 18 shows the update you would make to the web.xml file originally edited for Basic authentication.
Listing 18. The web.xml file edited for Digest authentication
<auth-method>DIGEST</auth-method> <realm-name>Digest Authentication Example</realm-name> </login-config> </web-app>
The only difference between Basic and Digest authentication is the specification of the authentication method, as shown in Listing 18. So, why would you prefer Basic over Digest? I haven't found a great answer for that. Digest is simply the more secure alternative.