Securing Your Web Application Requests Blog


    Security is a critically important requirement for most software and is something developers invest a great deal of time and energy into designing, developing, testing, and maintaining. The documentationintroducing the Spring Security framework (formerly named Acegi) describes application security quite well:

    Security is an ever-moving target, and it's important to pursue a comprehensive, system-wide approach. In security circles we encourage you to adopt "layers of security," so that each layer tries to be as secure as possible in its own right, with successive layers providing additional security. The "tighter" the security of each layer, the more robust and safe your application will be.

    While incorporating authentication, authorization, and input validation are no-brainers, most developers overlook a gaping hole: blindly trusting user input. Just because valid data was sent to the browser does not mean data returning from the browser hasn't been modified by the user in some inappropriate fashion. Although the average user pays no attention, application parameters within the browser's location bar are plainly visible, and nothing prevents a user from "customizing" a GET request before it's sent to the server. By the same reasoning, nothing prevents an advanced user from locally "customizing" a form and submitting an altered POST request. In making your application as secure as possible, it must be able to prevent such modifications.

    A solution to the problem is to secure the application in such a way that recognizing and manipulating sensitive data in generated URLs is not an option. This article presents a design that makes use of a customized JSTL tag to encrypt request parameters and values before they are sent to the browser and a servlet filter to perform decryption upon submission to the server. The result is an easy-to-use and nearly transparent system that adds an additional layer of security to your application.

    Although a very brief introduction of JSTL and servlet filters is provided, a general familiarity with both is assumed. Should you need to familiarize yourself with either, please see theResources section for some recommended introductory articles. No familiarity with cryptographic encryption or decryption algorithms is assumed.

    Custom JSTL Tag

    Rather than have developers repetitiously writing the common functionality found in nearly all Java-based web applications, Sun released the JSP Standard Tag Library (JSTL). Encouraging developers to move away from the Model 1 style of development with scriptlets, JSTL provides a standard implementation and usage syntax of this common functionality in the form of JSP tag libraries. JSTL has been widely adopted throughout the industry and other model-view-controller (MVC) frameworks, such as Spring Web MVC; Struts1 and 2, have similar libraries.

    One of the commonly used JSTL tags is the<c:url> tag, which is used to generate URLs within the application. Out of the box, the<c:url> tag offers prepending the name of the application's context path for creating absolute URL references, session management through URL rewriting, and URL encoding of request parameters. The <c:url> tag can optionally accept parameters, which it will use to dynamically generate the resulting URL.

    Because JSTL tags themselves are Java classes, they can be extended to provide customized or enhanced functionality. In this particular case, it is the <c:url> tag's ability to URL encode request parameters we are interested in overriding. But before discussing how we're going to implement the new functionality, let's cover conceptually how the<c:url> tag performs URL encoding. Each request parameter is composed of a name-value pair, such as:

    index.jsp?client_id=1824-67-04-F9#4$&client_name=Big Box Company

    To perform URL encoding, the <c:url> tag takes each individual request parameter value and passes it to a class that converts the value into theapplication/x-www-form-urlencoded MIME format (see the Java API and URLEncoder for more information). Next, this updated name-value pair is appended onto a Stringcontaining any previously encoded name-value pairs. The process is repeated for each name-value pair and after all have been processed. The aggregated String represents the URL encoded query String of the request. After encoding, the previous example is:


    Our customization of the <c:url> tag will perform a similar process, in which each request parameter undergoes processing to produce an updated queryString, with the difference being that each request parameter is cryptographically encrypted instead of being URL encoded. Let's look at the code.

    public class UrlEncryptedParameterTag extends UrlTag { ... private TextEncryptor textEncryptor = new BCodecTextEncryptor(); ... /** * Encrypts and adds a parameter under the name/key contained * within the encryptedParameterName property. * * @param name The parameter name. * @param value The parameter value. */ public void addParameter(String name, String value) { if (enabled) { logger.debug("Encrypting request parameter: " + name); StringBuilder sb = new StringBuilder(name); sb.append("="); sb.append(value); String encryptedNameValuePair = textEncryptor.encrypt(sb.toString()); value = URLEncoder.encode(encryptedNameValuePair, "UTF-8"); name = "enc"; } super.addParameter(name, value); } ... 

    Because we're modifying how parameters are added to the request, the above code only needs to override the addParameter(String name, String value) method of the<c:url>'s UrlTag class. The overridden method uses a StringBuilder (a Java 5 enhanced version of the StringBuffer) to concatenate a request parameter name-value pair, passes this value to a class that performs encryption, and passes the encrypted value tosuper.addParameter(). The resulting encrypted value is then bound to the HttpRequest under the parameter name of enc. From there, the tag proceeds as normal. The previous URL example becomes:


    Note that your application should avoid using the parameter nameenc, as it now indicates an encrypted parameter. While the chances that this is unacceptable within your application are small, the parameter name used is configurable.

    You can also see from the code that the overridden method does not perform the actual encryption itself and instead delegates to a separate class. This design allows for focused code and easy swapping of encryption algorithms. The next section will discuss the encryption component in closer detail.

    Encryption Component

    The custom JSTL tag delegates to a separate component the encrypting of the request parameters and values. The first step in creating this component is deciding the cryptographic strength your application requires. Because a large majority of applications manage fairly non-sensitive information, the first code sample will only use Base64 encoding. While not actually considered cryptographically secure, Base64 encoding does convert its input into a non-human-readable format and is, compared to truly cryptographically secure algorithms, quite fast.

    /** * Use Apache Commons Codec's BCodec to provide Base64 * encoding and decoding. */ public class BCodecTextEncryptor implements TextEncryptor { private BCodec bCodec = new BCodec(); /** * Encrypt the String. * * @param plaintext The input String you wish * to encrypt. */ public String encrypt(String plaintext) { try { return bCodec.encode(plaintext); } catch (EncoderException e) { throw new EncryptionOperationNotPossibleException(e.getCause()); } } /** * Decrypt the String. * * @param encryptedString The encrypted String * you wish you decrypt. */ public String decrypt(String encryptedString) { try { return bCodec.decode(encryptedString); } catch (DecoderException e) { throw new EncryptionOperationNotPossibleException(e.getCause()); } } }

    Undoubtedly there will be applications that require encryption of a higher strength. If you look at the above code carefully, you'll notice that TextEncryptor, the central interface of the encryption component, is provided by the open source Jasypt project. An easy-to-use library that provides a number of industrial-strength cryptographic algorithms without requiring detailed knowledge of how cryptography works, Jasypt also integrates with numerous open source projects such as BouncyCastle, Hibernate, Spring, and Spring Security. Although the sample codes defaults to using Base64 encoding, a setTextEncryptor(TextEncryptor textEncryptor) method is provided on both the custom JSTL tag and the decryption filter to allow the algorithm to be changed. Using Spring's dependency injection, for example, to manage this configuration, the following example conceptually demonstrates the required changes to use Jasypt'sStrongTextEncryptor:

    <bean id="textEncryptor" class="org.jasypt.util.text.StrongTextEncryptor"> <property name="password" value="servletRequestParameterDecyprtionFilter_password" /> </bean> <bean id="servletRequestParameterDecryptionFilter" class=""> <property name="textEncryptor" ref="textEncryptor" /> </bean> <bean id="urlEncryptedParameterTagBean" class=""> <property name="textEncryptor" ref="textEncryptor" /> </bean>

    Notice that no code changes were required to switch encryption algorithms.

    With the custom JSTL tag and encryption component in place, we now need a servlet filter to perform the decryption process before the request is handled by the application. We'll discuss this decryption servlet filter next.

    Decryption Servlet Filter

    A Java servlet filter acts as an interceptor and has the ability to modify or redirect an incoming request or outgoing response. Defined in the web.xml, filters are a flexible way to add powerful functionality to any application. With the JSTL encryption tag from a previous section acting as the first half of the process, a servlet filter is used as the second half of the process and modifies the incoming request to essentially perform the inverse of the custom JSTL tag. Before discussing the details, let's see the code.

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String encryptedParamtersStrings[] = ServletRequestUtils.getStringParameters(request, encryptedParameterName); for (String encryptedParametersString : encryptedParamtersStrings) { if (StringUtils.isNotBlank(encryptedParametersString)) { String decryptedParametersString = textEncryptor.decrypt(encryptedParametersString); decryptedParametersString = URLDecoder.decode(decryptedParametersString, "UTF-8"); Map<String, String> parameterMap = MapSupport.delimitedNameValuesStringToMap(decryptedParametersString, "&", "="); for (String attributeName : parameterMap.keySet()) { request.setAttribute(attributeName, parameterMap.get(attributeName)); } } } // Remove the encrypted name-value pairs from the request request.removeAttribute(encryptedParameterName); // Continue processing of the chain chain.doFilter(request, response); }

    Because not every parameter received by your application is encrypted, the filter must be capable of handling both encrypted and unencrypted parameters. Since we know that the custom JSTL tag encrypts parameters and binds them to the request under the parameter name of enc, any parameter in the request under the this name is decrypted and any parameter under any other name is left untouched. The servlet filter, similar to the custom JSTL tag, delegates to the encryption component, which performs the cryptographic process. This decrypted value will be the original request parameter name-value pair as it was before being encrypted by the custom JSTL tag. The servlet filter then binds this name-value pair to the request under the original parameter name. The request name-value pair has now been returned to its original state and, in effect, it is as if no encryption/decryption process ever took place. From here on, your application will function normally with no knowledge that an additional layer of security was added.


    This additional security doesn't come without a cost, of course. By performing encryption in the custom JSTL tag and decryption in the servlet filter, a performance penalty is incurred on each incoming request and outgoing response. Unfortunately, this obviously will reduce the performance and scalability of your application.

    If your application can not afford a degradation in performance, the loss can be minimized by making some informed choices. First, evaluate if all request parameters throughout your application require being secured. Chances are not all of them will, and between the two extremes of encrypting everything and encrypting nothing, choose to encrypt only the information that is sensitive or valuable enough to warrant protection. Second, as previously mentioned, evaluate the encryption algorithm used. Once you decide that a particular parameter should be encrypted, is a high-strength algorithm required, or will a computationally lighter algorithm suffice?

    Additionally, nothing but a little extra effort prevents you from creating multiple tag-filter pairs, each pair with a varied level of encryption, allowing you to pick and choose a level of encryption appropriate to the sensitivity of what's being encrypted. One tag-filter combination could use a cryptographically insecure but computationally fast algorithm for the majority of the application and another tag-filter combination could use slower-performing but stronger encryption for your most sensitive data. The use of multiple algorithms will improve the overall security by increasing the workload for someone wishing to circumvent the system.


    The security of your application is a big deal and your system, as the old saying goes, is only as strong as its weakest link. By using a customized JSTL tag, a servlet filter, and a flexible way to swap encryption algorithms, this article showed how to add an additional layer of security that transparently encrypts and decrypts application request parameters and values to prevent users from altering browser requests. Although we focused on the use of JSTL, the concept could be applied to other tag libraries such as those used with Struts 2. Similarly, although the example extended JSTL's <c:url> tag used for dynamic URL generation, the concept could also be applied to a form generation tag and be used to secure form data.