Open SourceTop 7 Features in Tomcat 7: The New and the Improved

Top 7 Features in Tomcat 7: The New and the Improved

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Tomcat 7 introduced a number of new features as well as enhancements to existing features. Several articles list the new Tomcat 7 features, but most don’t explain them in detail, critique them, or provide working code examples. Rather than just list the new features, this article will identify the seven most notable Tomcat 7 features and enhancements, critique them, and present examples of working code that you can use to get a better understanding of each feature/enhancements.

The features are categorized as either “New Tomcat 7 Features: Revolutionary Changes” or “Tomcat 7 Enhancements: Evolutionary Changes” as follows:

New Tomcat 7 Features: Revolutionary Changes

1. Use of a nonce to prevent cross-site request forgery (CSRF) attacks

2. Changing the jsessionid on authentication to prevent session fixation attacks altogether

3. Memory leak detection and prevention

4. Use of aliases to store static content outside the war file

Tomcat 7 Enhancements: Evolutionary Changes

5. Servlet 3.0, JSP 2.2 and JSP-EL 2.2 support

6. Easier to embed Tomcat in your applications, e.g. in JBoss

7. Asynchronous logging

According to Mark Thomas, Release Manager and Committer for Tomcat 7, the three most compelling features of Tomcat 7 are Servlet 3.0, memory leak prevention and detection, and improved security.

The attached Tomcat 7 Demo file contains an Eclipse project and an Ant build file, which you can use to build a war. The Eclipse project has sample code that illustrates two of the new features in Tomcat 7.

The rest of the article is devoted to detailed discussions of the seven most notable new features and enhancements.

New Tomcat 7 Features: Revolutionary Changes

This section discusses the four previously identified new features.

1. Use of a Nonce to Prevent Cross-Site Request Forgery (CSRF) Attacks

Webopedia defines Cross Site Request forgery (CSRF) as follows: “a type of malicious attack that affects Web-based applications. A CSRF attack typically forces users to execute unwanted actions while they are logged into a trusted Web site.” An even more descriptive term for CSRF is session riding.

The classic way to prevent CSRF has been to use a nonce, which Wikipedia defines as “a random or pseudo-random number issued in an authentication protocol to ensure that old communications cannot be reused in replay attacks.”

Tomcat 7 has a servlet filter, which stores a nonce in the user’s session after every request has been processed. This nonce must be added as a request parameter for each subsequent request. The servlet filter then checks whether the nonce in the request parameter is the same as the nonce stored in the user session. If they are the same, the request could have come only from the given site. If they are different, the request is from some other site and is rejected.

The servlet filter is very simple. Here is a snippet of the relevant source code (from Apache Software Foundation CsrfPreventionFilter documentation):

public class CsrfPreventionFilter extends FilterBase {...public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {... String previousNonce = req.getParameter(Constants.CSRF_NONCE_REQUEST_PARAM); String expectedNonce = (String) req.getSession(true).getAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME);  if (expectedNonce != null && !expectedNonce.equals(previousNonce)) { res.sendError(HttpServletResponse.SC_FORBIDDEN); return; }  String newNonce = generateNonce();  req.getSession(true).setAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME, newNonce);...

So every URL has to include a nonce extracted from the user session. Here is an example using JSP-EL:

Before:

< c:url var="url" value="/show" > < c:param name="id" value="0" / >< /c:url >< a href="${show}" >Show< /a >

After:

< c:url var="url" value="/show" > < c:param name="id" value="0" / > < c:param name="org.apache.catalina.filters.CSRF_NONCE" value="${session.org.apache.catalina.filters.CSRF_NONCE}" / >< /c:url >< a href="${show}">Show< /a >

See the attached Tomcat 7 Demo with the sample project for a working example. The filter is configured in the web.xml file. With the filter in place, all requests to the http://localhost:8080/tomcat7demo/csrf/ URL without the nonce as a request parameter will lead to a 403 error (“forbidden”).

An invalid request (e.g. in email spam) cannot have the nonce. So, a session riding attack cannot work. Even if the user clicks on a malicious link or posts a malicious form, the request will be denied because the nonce will not be there. The nonce will be present only in Web pages returned by this Web app.

The downside of this approach is that the nonce is required as a request parameter for all URLs.

2. Changing the jsessionid on Authentication to Prevent Session Fixation Attacks

A session fixation attack happens like this:

  1. A Malicious user visits a website. A cookie is stored with the jsessionidin the browser — even if the user doesn’t log in. He then crafts a URL with the jsessionid in the URL and sends it to the victim (e.g. http://example.com/login?JESSIONID=qwerty).
  2. The victim clicks on the URL with the jsessionid and is prompted for the authentication details. He logs in.
  3. The malicious user now can use the URL with the jsessionid and will be logged in as the victim.

It is trivial for the attacker to add a jsessionid in the URL as well as to send it in the header using a malicious form. (For a full description of session fixation attacks, read the whitepaper “Session Fixation Vulnerability in Web-based Applications” from Acros Security.)

The solution implemented by the Tomcat team is a patch that changes the jsessionid after authentication. This patch has been applied to Tomcat 7 and has also been backported to Tomcat 5 and 6 with some differences.

According to Mark Thomas, the results of this patch in Tomcat 7 are:

  • Tomcat is not vulnerable by default because the session ID changes upon authentication.
  • If this default is changed by the user (e.g. because the application can’t handle a changing session ID), then the risks may be minimized by disabling session tracking via URL (a new feature in Servlet 3).

And in Tomcat 5 and 6, the results of the patch are:

  • Session fixation attacks can be prevented by enabling Tomcat to change the session ID on authentication (if there is insufficient support for this to be enabled by default).
  • If the application can’t handle a changing session ID then the risks may be minimized by writing a custom filter that checks request.isRequestedSessionIdFromURL() and responds accordingly (e.g. rejecting the request).

The above changes work transparently behind the scenes; the developer does not have to do anything. The users session (jsessionid) is changed after login. This completely prevents session fixation attacks.

3. Memory Leak Detection and Prevention

Developers deploying updated versions of Web applications in their development environment usually encounter Permgen space: OutOfMemoryError. This is caused by memory leaks. The classes from a previous deployment are not completely garbage collected. Developers work around this by increasing the amount of PermGen memory or restarting Tomcat.

Tomcat 7 introduced a new feature to fix some of the common causes of memory leaks from the PermGen space by removing references to objects that don’t get garbage collected. This feature is intended for developers deploying applications to Tomcat in their development environments. In development environments, to save time developers try to redeploy to new war files without restarting Tomcat. In production deployments, it is a good practice to stop Tomcat, clear the work folder and deploy the new application.

The memory leak detection and prevention feature is not perfect, however. There are still scenarios where Tomcat cannot do anything to fix memory leaks and does not detect them. So for production systems, it is still a good practice to stop Tomcat, clear the work folder and the old Web app, deploy the new Web app and restart Tomcat.

Mark Thomas explains that the application or library code that can trigger this situation include:

  • JDBC driver registration
  • Some logging frameworks
  • Storing objects in ThreadLocals and not removing them
  • Starting threads and not stopping them

There are also a number of places where using the standard Java API can trigger a similar issue. These include:

  • Using the javax.imageio API (the Google Web Toolkit can trigger this
  • Using java.beans.Introspector.flushCaches() (Tomcat does this to prevent memory leaks caused by this caching.)
  • Using XML parsing (the root cause is unknown due to a bug in the JRE)
  • Using RMI (somewhat ironically causes a leak related to the garbage collector)
  • Reading resources from JAR files

4. Use of Aliases to Store Static Content Outside the War File

A Web application might need static resources such as CSS, JavaScript, and video and image files. These are usually included inside the bundled war file. This increases the size of the war file and also leads to duplication of static resources. An alternative to this approach has been to use Apache HTTP server to host static content. This extract from the Apache httpd.conf shows aliases:

< Directory "/home/avneet/temp/static" >Order allow,denyAllow from all< /Directory >Alias /static "/home/avneet/temp/static"

The Apache directive above will make the contents of the /home/avneet/temp/static folder available under the http://localhost/static/ URL.

Tomcat 7 now offers an alternative to this. Tomcat 7 allows a new aliases attribute in the context element. This attribute can point to a static resource. You can now access it using Classloader.getResourceAsStream('/static/...') or embed a link to it and let Tomcat resolve the absolute path. Here is an example of context.xml:

< ?xml version="1.0" encoding="UTF-8"? >< Context path="/tomcat7demo" aliases="/static=/home/avneet/temp/static" >...< /Context >

Assume that the /home/avneet/temp/static folder contains an image bg.png and the context.xml file has been configured as shown above.

If the war file is deployed as tomcat7demo, you can now access this mapped image resource in the following three ways:

  1. Directly: http://localhost:8080/tomcat7demo/static/bg.png
  2. Embed a link in an HTML page: < img src="/tomcat7demo/static/bg.png" / >
  3. In Java code: ByteArrayInputStream bais = (ByteArrayInputStream)getServletContext().getResourceAsStream("/static/bg.png");

The advantages of using aliases instead of Apache aliases in httpd.conf is that the mapped resources can be accessed from within a servlet, and the aliases can be used for applications that don’t have Apache at the front.

Tomcat 7 Enhancements: Evolutionary Changes

This section discusses the three previously identified enhancements.

5. Servlet 3.0, JSP 2.2 and JSP-EL 2.2 Support

The enhancements in Servlet 3.0 are:

  • Ability to use POJOs as servlets and/or filters using annotations (web.xml is not required)
  • Ability to describe deployment in Web fragments — Web fragments are XML files with only partial deployment information. The servlet engine composes the final web.xml from these Web fragments. This is expected to reduce complexity in web.xml files.
    As an example, struts.jar and spring-mvc.jar could each have a web-fragment.xml.The developer will not have to configure struts/spring-mvc in the web.xml. The web-fragment.xml in the JAR files will be automatically detected and the struts/spring-mvc servlets and filters will be auto-configured.
  • Async processing of Web requests — This feature was available in Tomcat 6 but it has now been standardized in Servlet 3/Tomcat 7, making Web applications that use async I/O portable across Web containers. This uses non-blocking I/O, and every HTTP connection doesn’t require a thread. Fewer threads can serve more HTTP connections. This is particularly beneficial where the HTTP request triggers a long-running process and then returns a result (e.g. report generation, slow databases, Web service calls).
  • Security-related changes — Servlet 3.0-compliant containers can now use SSL for session tracking instead of cookies and URL rewriting.

DevX published an excellent explanation of Servlet 3.0 changes.

6. Easier to Embed Tomcat in Your Applications

Tomcat can be embedded in an application and it can be configured and started programmatically. Most of the configuration in CATALINA_HOME/conf/server.xml has to be done programmatically. Prior to Tomcat 7, Tomcat 6 provided an Embedded class, which had convenience methods to configure Tomcat. This class has been deprecated. The new class Tomcat uses defaults for several config elements and provides an easier and simpler way to embed Tomcat.

Here is the general structure of Tomcat configuration elements from CATALINA_HOME/conf/server.xml and some relevant attributes:

< Server > < Service > < Connector port="8080 > < Engine > < Host appBase="/home/avneet/work/tomcat7demo/dist" / > < /Engine > < /Connector > < /Service >< /Server >

To configure these programmatically, you have to build all the objects above and configure them. Here is the Java code to do this:

final String CATALINA_HOME = "/home/avneet/work/temp/tomcat7demo/"; Tomcat tomcat = new Tomcat(); tomcat.setBaseDir( CATALINA_HOME ); tomcat.setPort( 8080 ); tomcat.addWebapp("/tomcat7demo", CATALINA_HOME + "/webapps/tomcat7demo.war");

tomcat.start(); System.out.println("Started tomcat"); tomcat.getServer().await(); //Keeps Tomcat running until it is shut down //Webapp tomcat7demo accessible at http://localhost:8080/tomcat7demo/

7. Asynchronous Logging

Tomcat 7 now includes an asynchronous file logger (AsyncFileHandler). AsyncFileHandler extends FileHandler and can be used in place of FileHandler. To use AsyncFileHandler, simply replace all occurrences of FileHandler with AsyncFileHandler in the CATALINA_HOME/conf/logging.properties file. The application must use java.util.Logging; asynchronous logging does not work with Log4j.

When a log message is sent to the AsyncFileHandler, the log message is added to a queue(java.util.concurrent.LinkedBlockingDeque) and the method invocation to log a message returns immediately without waiting for the I/O to disc. A separate thread is started when the AsyncFileHandler is loaded by the class loader. This thread reads log messages from the queue and writes them to the disc.

The advantage of this approach is that if the I/O to disc is slow (e.g. log files on a remote drive), logging will not slow request processing.

AsyncFileHandler employs a producer/consumer relationship with the queue to store log messages. The default queue size is 10000. In case of overflow, the default behavior is to drop the last message. Both the default size and overflow behavior can be configured using startup system properties.

About the Tomcat 7 Demo Application

The attached Tomcat 7 Demo Web application has two servlets. One servlet is demonstrates how to use a nonce to prevent CSRF, and the second illustrates the use of aliases. Update the web/META-INF/context.xml file to point to the absolute folder where the images are (e.g. ./images).

Build the war file using build.xml and deploy it in Tomcat 7. Use the two URLs below to see CSRF filtering and aliases in action:

  • http://localhost:8080/tomcat7demo/csrf/
  • http://localhost:8080/tomcat7demo/alias/

Conclusion

The Tomcat team introduced several changes in Tomcat 7 in terms of both new features and enhancements to existing features. The changes had not been tested in production systems at time of writing (the latest stable release was 7.0.2), but in 6-12 months they will be mainstream and make it easier for developers to deploy more secure, high-quality Java-based Web applications.

About the Author

Avneet Mangat has 9 years of experience in Java/J2EE development and currently works as an independent IT consultant in London. He holds a master's degree in software engineering from University of Oxford, and is a Sun-Certified Java Programmer, Web Component Developer and Enterprise Architect, an Adobe-certified Flash Designer, and is Prince2 certified (foundation). He is the lead developer of the open source tool DBBrowser.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories