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

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) attacks2. Changing the jsessionid on authentication to prevent session fixation attacks altogether3. Memory leak detection and prevention4. 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 support6. Easier to embed Tomcat in your applications, e.g. in JBoss7. 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:

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). The victim clicks on the URL with the jsessionid and is prompted for the authentication details. He logs in. 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.)

(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:

Directly: http://localhost:8080/tomcat7demo/static/bg.png Embed a link in an HTML page: < img src="/tomcat7demo/static/bg.png" / > 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.

Page 1 of 2