Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Restoring Security in Tomcat with BadInputFilter

Here, we proposed an update and correction of BadInputFilter. To limit the scope of the article, we focus on the original implementation of BadInputFilter book Brittain and Darwin.

Designed for Tomcat 6, the BadInputFilter provides a front line of defense against security breaches of common web applications such as SQL injection attacksand cross-site scripting. Unfortunately, the BadInputFilter breaks the silence in later implementations of Tomcat. In this article, learn how to restore the security benefits of the BadInputFilter for all versions of Tomcat, and even for use in other Servlet/JSP container.

Some technical books are more useful than others, but one that is, in fact, extremely useful is "Tomcat: The Definitive Guide (second edition)" by Jason Brittain and Ian F. Darwin. Even this book being written for Tomcat 6, most of it is still applicable for Tomcat 7, currently the latest stable version. If you use Apache Tomcat this book is an invaluable reference.

Brittain & Darwin provide a thorough introduction to the configuration and implementation of Apache Tomcat in production environments. The book also provides the source code for a couple of useful classes named BadInputFilter and BadInputValve, which can be used to filter potentially dangerous requests. The problem is that these two classes rely on knowledge that is specific to Tomcat 6. In newer versions of Tomcat, BadInputValve does not compile, and a part of the functionality provided by BadInputFilter no longer works. Both the original version of BadInputFilter and an updated version available on SourceForge have this problem. In addition, the failure of BadInputFilter is silent, in the sense that there is no indication that he is no longer part of their work.

Here, we proposed an update and correction of BadInputFilter. To limit the scope of the article, we focus on the original implementation of BadInputFilter book Brittain and Darwin. You can use a similar approach to an updated implementation with some changes that are quite simple. In fact, you will find two versions of BadInputFilter updated in the source code that accompanies this article. In com.mrbool.filter package, BadInputFilter corresponds to the original implementation and the BadInputFilter2 corresponds to the updated implementation currently hosted on SourceForge.

We will assume that you have programmed in Java and have some familiarity with the use of Java-based technology for web applications like Servlets, JSPs, and so on. I also assume that you know what role it plays in Tomcat these types of applications. Provide a brief introduction to filters, in order to give the context for the rest of the article.

Filters and Valves

So what is a filter? As described in the Javadoc for the Filter interface, a filter is an object that does the filtering tasks either on the request for a resource (for example, a servlet or an html file) or in response to an appeal or both. More than one filter can be applied in a chain to a resource or a collection of resources, which is an excellent example of the standard chain of responsibility. Figure 1 illustrates the use of filters in a web application.

Filters in a Java Web application

Figure 1. Filters in a Java Web application.

Examples of uses for filters include:

  • authentication
  • Logging and auditing
  • data compression
  • encryption

One of the cool things about filters is that they can be added to an application after the fact. For example, suppose you have an existing web application, and you decide you want to record some special messages when the applications are received by certain web resources. You can rewrite the part of the application that serves these features, or you can simply write a filter that intercepts requests for resources, records the message and then forwards the request to be treated in the normal way. In the second approach the existing web application remains unchanged except for the deployment descriptor of the web application, an XML file named web.xml which specifies the existence of the filter and the resources to apply.

Valves are similar to filters except for three very important differences:

  1. Valves are specific to Tomcat and therefore run only in the container Servlet/JSP. Filters, on the other hand, are part of the Java Servlet specification, and are designed to be independent of any Servlet/JSP container, so they are portable to other Servlet/JSP container, and also to Tomcat. Unfortunately, the code for BadInputFilter depends on Tomcat 6 implementation details, what has changed with the latest versions of Tomcat.
  2. If your architecture is composed of several web applications on the same Tomcat server, the valves can be configured in one place to filter requests from all or some of them. The filters must be configured separately for each web application.
  3. Filters are easily configured to run on specific URL patterns. Valves require you to write your own code corresponding to this purpose.

Using BadInputFilter for web application security

If a web application is not designed with security as a requirement in mind, it is likely to be vulnerable to external security attacks, cross-site scripting (XSS), HTML injection, and SQL injection. The BadInputFilter is designed to check the potentially dangerous user input and filter the bad requests. Although you should probably take additional security measures, you can think of BadInputFilter as a first line of defense for some security holes of well known web applications.

Essentially, BadInputFilter analyzes user requests for possible problems. If a problem is found, it performs one of two actions - either (1) that prohibits the solicitation or (2) which falls outside the entrance of bad user. Performing these actions in a filter allows you to implement the code once and then easily apply it to several (or all) of the features within the same web application.

Prohibiting the user input can be done by sending an HTTP response status code 403 (Forbidden) to the client. For example, if the user input contains certain characters of non-printing control, you probably want to deny the request altogether. Part of BadInputFilter prohibiting certain characters within the user input will continue to function properly. But the second part, the part that escapes the entrance of bad user, will fail.

Where the failure BadInputFilter

A series of web security breaches involve the introduction of characters or phrases that have special meaning within the context of HTML, JavaScript, or SQL. For example, if the user input is not properly validated or escaped, you can enter the JavaScript that runs on the server or that reveals information about the server environment. As an example, escaping user input, you may want to look at all the left angle brackets occurrences or right ("") and replace them with HTML entities/XML equivalent ("", respectively). Thus, user input containing the (indicating possible JavaScript code) would be harmless in most cases, but still fairly presents echoed back to the user as part of an HTML response page.

In his book, Darwin Brittain provides a test JSP page (input_test.jsp) that can be used to see how the various user input filtered and unfiltered are treated. Configuring BadInputFilter to filter requests for this test page shows that BadInputFilter no longer escape user input as originally planned. The reason the BadInputFilter flaw is that it relies on Tomcat 6 implementation details.

Here is a brief description, from an implementation perspective, of why the BadInputFilter failed. Filters have access to user input through a type HttpServletRequest object. For a HttpServletRequest object, the getParameterMap() method must return an immutable Map containing the parameter names and values. In Tomcat 6, the immutability of the object could be circumvented through reflection to gain access to setLocked() method and then using it with a false parameter, simply unlocks the immutable map. With Map unlocked, it was possible to change the names and/or parameter values. In later versions of Tomcat, using this approach to unlock and modify the request parameters would not work, but the failure is silent. There is no apparent fault indication anywhere in the system, or on a web page or in a log file. User input is simply passed unchanged - meaning it is not escaped.

Modifying the BadInputFilter to escape user input

As already described, HttpServletRequest has a method called getParameterMap() which returns an immutable Map, thus mapping the parameter names to values. But in order to "escape" user input, you need to be able to modify these names and/or parameter values. The question is how to modify an immutable Map. Obviously, you can not modify the map directly (or at least you should not be able to modify the map), but you can wrap around the HttpServletRequest in a HttpServletRequestWrapper, which can be passed on to the target resource in place of the original request. The request "wrapped" (wrapped) copies and escapes the names of the original parameters and values that the target resource, then have access.

Let''s look at the code to fix the problems with the BadInputFilter as two Java classes. The first class, FilterableRequest extends HttpServletRequestWrapper, in order to provide access to and modification (escape) of the request parameters. The FilterableRequest builder makes a local copy of the Map HttpServletRequest parameter that encapsulates it. It then replaces the inherited methods that provide access to Map so that they use the local copy. Methods inherited still treat the Map parameter as immutable, but the FilterableRequest also provides a new method, getModifiableParameterMap(), which allows the modification of parameters. Listing 1 is the source code needed to build the FilterableRequest.

Listing 1. Creating the FilterableRequest

package com.mrbool.filter;

import java.util.*;
   import javax.servlet.http.*;

   /**
    * Wraps an HttpServletRequest so that parameters can
    * be modified by a filter.
    *
    * @author John I. Moore, Jr.
    */
   public class FilterableRequest extends HttpServletRequestWrapper
     {
       private Map<String, String[]> parameters = null;

       /**
        * Construct a wrapper for the original request.
        *
        * @param request the original HttpServletRequest
        */
       public FilterableRequest(HttpServletRequest request)
         {
           super(request);
           parameters = new TreeMap<String, String[]>();
           parameters.putAll(super.getParameterMap());
         }

       @Override
       public String getParameter(final String name)
         {
           String[] values = parameters.get(name);
           return values != null ? values[0] : null;
         }

       @Override
       public Map<String, String[]> getParameterMap()
         {
           return Collections.unmodifiableMap(parameters);
         }

       /**
        * Returns a ParameterMap that can be modified.
        */
       protected Map<String, String[]> getModifiableParameterMap()
         {
           return parameters;
         }

       @Override
       public Enumeration getParameterNames()
         {
           return Collections.enumeration(parameters.keySet());
         }

       @Override
       public String[] getParameterValues(final String name)
         {
           return parameters.get(name);
         }
     }

Whereas parts of the implementation of BadInputFilter still work properly (eg, boot code, and the part that prohibits the user input by sending an HTTP response status code 403), the easiest way to illustrate the correction for the version of Jason Brittain of BadInputFilter is to create a new version, which extends the original version and then just replace the methods that need to change. (This approach is known as implementation inheritance.).

The source code for the new version of BadInputFilter is shown in Listing 2. The essence of the changes can be summarized in:

  1. In the doFilter () method, we create a FilterableRequest involving the HttpServletRequest parameter and then passes this FilterableRequest to FilterParameters method as follows:
FilterableRequest filterableRequest = new FilterableRequest((HttpServletRequest) request);
  filterParameters(filterableRequest);
  1. In FilterParameters () method, call the getModifiableParameterMap () on the filterable request to have access to parameters instead of trying to "unlock" the immutable map using reflection.

Essentially, the rest of the code in these two methods is only slightly modified from the implementation of the original BadInputFilter. Listing 2 shows the source code for these two methods in our BadInputFilter version.

Listing 2. Updating the BadInputFilter

@Override
   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain filterChain) throws IOException, ServletException
     {
       // Skip filtering for non-HTTP requests and responses.
       if (!(request instanceof HttpServletRequest)
           || !(response instanceof HttpServletResponse))
         {
           filterChain.doFilter(request, response);
           return;
         }

       // Only let requests through based on the allows and denies.
       if (processAllowsAndDenies(request, response))
         {
           // Filter the input for potentially dangerous JavaScript
           // code so that bad user input is cleaned out of the request
           // by the time Tomcat begins to perform the request.
           FilterableRequest filterableRequest
               = new FilterableRequest((HttpServletRequest) request);
           filterParameters(filterableRequest);

           // Perform the request.
           filterChain.doFilter(filterableRequest, response);
         }
     }

   /**
    * Filters all existing parameters for potentially dangerous content,
    * and escapes any if they are found.
    *
    * @param request The FilterableRequest that contains the parameters.
    */
   public void filterParameters(FilterableRequest request)
     {
       Map<String, String[]> paramMap = request.getModifiableParameterMap();

       // Loop through each of the substitution patterns.
       for (String patternString : parameterEscapes.keySet())
         {
           Pattern pattern = Pattern.compile(patternString);

           // Loop through the list of parameter names.
           for (String name : paramMap.keySet())
             {
               String[] values = request.getParameterValues(name);

               // See if the name contains the pattern.
               boolean nameMatch;
               Matcher matcher = pattern.matcher(name);
               nameMatch = matcher.find();
               if (nameMatch)
                 {
                   // The parameter’s name matched a pattern, so we
                   // fix it by modifying the name, adding the parameter
                   // back as the new name, and removing the old one.
                   String newName = matcher.replaceAll((String) parameterEscapes
                       .get(patternString));
                   paramMap.remove(name);
                   paramMap.put(newName, values);
                   servletContext.log(“Parameter name “ + name
                       + “ matched pattern \”” + patternString
                       + “\”.  Remote addr: “
                       + ((HttpServletRequest) request).getRemoteAddr());
                 }
             }

           // Loop through the list of parameter values for each name.
           for (String name : paramMap.keySet())
             {
               String[] values = request.getParameterValues(name);
               // Check the parameter’s values for the pattern.
               if (values != null)
                 {
                   for (int j = 0; j < values.length; j++)
                     {
                       String value = values[j];
                       boolean valueMatch;
                       Matcher matcher = pattern.matcher(value);
                       valueMatch = matcher.find();
                       if (valueMatch)
                         {
                           // The value matched, so we modify the value
                           // and then set it back into the array.
                           String newValue;
                           newValue = matcher.replaceAll((String)
                               parameterEscapes.get(patternString));
                           values[j] = newValue;
                           servletContext.log(“Parameter \”” + name
                               + “\”‘s value \”” + value
                               + “\” matched pattern \””
                               + patternString + “\”.  Remote addr: “
                               + ((HttpServletRequest) request).getRemoteAddr());
                           servletContext.log(“newValue =” + newValue);
                         }
                     }
                 }
             }
         }
     }

Configuring BadInputFilter

The book Brittain & Darwin contains sample configuration settings for the BadInputFilter that can be added to the deployment descriptor web application (web.xml). Listing 3 shows an example of configuration code given in the book.

<filter>
     <filter-name>BadInputFilter</filter-name>
     <filter-class>com.oreilly.tomcat.filter.BadInputFilter</filter-class>
     <init-param>
       <param-name>deny</param-name>
       <param-value>\x00,\x04,\x08,\x0a,\x0d</param-value>
     </init-param>
     <init-param>
       <param-name>escapeQuotes</param-name>
       <param-value>true</param-value>
     </init-param>
     <init-param>
       <param-name>escapeAngleBrackets</param-name>
       <param-value>true</param-value>
     </init-param>
     <init-param>
       <param-name>escapeJavaScript</param-name>
       <param-value>true</param-value>
     </init-param>
   </filter>
   <filter-mapping>
     <filter-name>BadInputFilter</filter-name>
     <url-pattern>/input_test.jsp</url-pattern>
   </filter-mapping>

The minimum change necessary to use our version of BadInputFilter is replace com.oreilly.tomcat.filter.BadInputFilter by com.mrbool.filter.BadInputFilter in the setting. In addition, it is worth considering some other possible changes to both the Listing 3 configuration code or the original source BadInputFilter.

First, Eclipse Kepler (4.3.1) and the Java 7 will give several warnings related to generics when compiling the original version of BadInputFilter. This is not surprising, because the original code was written when generics were relatively new to Java. At one point in the original code of Jason Brittain SuppressWarnings there is a note to get rid of such notice, but other warnings are now. There are several ways to get rid of these warnings, but following the Jason code can simply add SuppressWarnings notes as follows:

  1. AddSuppressWarnings ("rawtypes") before processAllowsAndDenies() method.
  2. Replace @SuppressWarnings(“unchecked”) with @SuppressWarnings({ “unchecked”, “rawtypes” }) before method filterParameters.
  3. Remove @SuppressWarnings(“unchecked”) from the middle of method filterParameters() since the change in item 2 above makes it redundant.

Conclusion

If you develop and/or maintain a website that is open to the public, you should anticipate that someone will try to break it at some point in time. One way to reduce the vulnerability of your website is by validating all user input. The BadInputFilter class was originally designed to provide a defensive front line for several security flaws in web applications well known for applications for filtering and prohibiting the application or escape potentially malicious input. With the latest versions of Tomcat, a part of the functionality provided by BadInputFilter no longer works. In this article we have seen some changes to the BadInputFilter that will restore the lost functionality. Moreover, unlike the original version of BadInputFilter, the updated version does not depend on the implementation of the Tomcat and should work correctly on any Servlet/JSP container.



Web developer and passioned for web design, SEO and front end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login