Storing Session State on the Client

Greg Murray, Inderjeet Singh

Problem Description

Web applications often need to maintain session state that spans more than one request. Generally, session state in a J2EE[TM] application can be stored in any of these tiers:

Each tier has benefits and weakness for storing session state. An application can store session state in more than one tier and can choose to partition the session state among different tiers. Because storing state on the web tier with HttpSession is a well-known topic, and other choices like using stateful session beans have been discussed in many places, this solution focusses on storing session state on the client tier. This solution is useful when your application needs to store session state on the client side instead of, or in addition to, using HttpSession to hold the session state. One of the key requirements of this solution is that the state is stored securely and this solution achieves that.

Solution

There are several ways for a web application to store session state on the client tier. One possible solution is to use Cookies to store the state on the client. However, cookies have limitations in size and are not ideal in cases where you want to store session state on the client.

A more robust mechanism can be designed by using hidden form fields in HTML, some code for serializing and deserializing, an encoder, and a few other tricks. Both URL parameters and the Java objects need to be encoded so that a view can be regenerated exactly as it was left. This solution can provide a reusable means for web applications to store state on the client. Lets briefly sketch a solution and example.

HTML provides a means for placing state in forms as hidden fields. This state can later be retrieved on a subsequent POST. Code Example 1 shows how hidden fields are used to store state in an HTML form:

<form action="controller.do" method="POST">
<input type="HIDDEN" name="var1" value="value 1">
<input type="SUBMIT" value="Push Me">
</form>

Code Example 1: Using Hidden Form Fields to Store Session State

In the case of the above code example, clicking the Push Me button causes the form and the data to be submitted as an HTTP POST to the web component mapped to controller.do. Note that using the HTTP GET method instead of POST does not work with this solution because GET encodes all form fields as URL parameters creating a very long URL that may exceed the length supported by most common browsers and web containers. Also remember that the HTTP GET method should be used for requests that are considered idempotent, allowing the requests to be cached locally and by intermediaries. You can create links that appear to be <a href="someurl"> tags, but use JavaScript[TM] events associated with them to post the form containing the client-side state. A link to submit the form Code Example 1 would be the following:

 <a href="#" onclick="document.forms[0].submit(); return false;">

The Java[TM] language provides a mechanism for serializing objects so that they can be recreated in the same state as they were at a earlier point in time. Combined with an encoding scheme, the serialized content is placed in the HTML pages sent to a client. In the case of the example above, the encoded serialized data would be placed as the value of attribute var1. The serialized content can also be compressed if the amount of data being stored in the page is large.

The web component to which the form is POSTed (a servlet mapped to controller.do in the  example above) may access the hidden form variables using the HttpServletRequest API. The web component may deserialize the state and perform some action based on that state.

Client-side state can be used to reduce the amount of data stored in the HttpSession. It helps spread the state over a number of web pages, all of which are kept on the client-side. This can help reduce the memory requirements at the server, which increases scalability. However, not all state is appropriate to be moved to the client. Note the following while using client-side state:

Some states that would be ideal for storing on the client includes page-specific states such as objects (JavaServer[TM] Faces uses the client state in hidden form elements technique as an option for storing view state). User specific objects that might normally be kept in the HttpSession, and objects such as shopping carts, search results, wish lists, and user information may be good candidates. States such as web application configuration state, large objects such as those containing images, or objects shared among users should not be kept on the client.

Storing state on the client may not be the best solution for you. There are performance penalties and bandwidth usage associated with storing state on the client. Consider storing state using the strategies described in this document on a case-by-case basis.

Securing Client-Side State

Any state that is stored on the client is susceptible to various kinds of attacks, such as the following:

Attacks in transit can be mitigated by using HTTPS for all the web pages that store client-side state. A more robust approach to eliminate both types of attacks is to ensure that the data stored on the client is unreadable and unmodifiable by anyone except the server. This can be achieved by encrypting the data and attaching a message authentication code (MAC) to it. The data is then converted into text by using base64 encoding. This text is then stored in the hidden form fields in the HTML that is sent to the client. If the data needs to be compressed, then the compression should be applied before the encryption is performed. This is done because the encryption process randomizes the data values, which results in an output that can not be compressed further. See the section on Securing Client-Side State in the document on design details for how this is done.

Custom Tag With Servlet Strategy

Although the code for storing session state can be directly embedded in the JSP page and the web tier classes, it is more approprite to put this code into a custom tag for reuse. Encoding the URL parameters and Java objects, along with generating the HTML forms with the necessary hidden fields in such a way that they can be reconstituted upon subsequent requests, can be  somewhat tedious. A reusable custom tag library can hide the complex details needed to do the serialization and encoding of URL parameters and conversational state.

For more details on implementing this strategy see the Client Side State Design Details document.

References

For more information about this topic, refer to the following:

© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.