4.10 Usage Patterns

 <  Day Day Up  >  

The declarative and programmatic security features supported by the Java Servlet specification are used in various ways within enterprise environments. Based on the need, common usage patterns can be used. This section discusses a few usage patterns that have emerged out of common use cases within Web application environments. The patterns identified include connecting to other HTTP servers via HTTPS connections, maintaining the state securely, and performing secure pre- and post-servlet processing.

4.10.1 Using HTTPS to Connect to External HTTP Servers

URL connections from servlets to external HTTP servers can be established programamtically using the java.net.URL class. The URL to connect to is passed as a String argument to the URL constructor. Most URLs start with the string http:// . When URL connections need to be made over SSL, the protocol is HTTPS, and the URL starts with the string https:// . By default, a URL starting with https:// would result in an error ”a java.net.MalformedURLException would be thrown ”unless an HTTPS protocol handler has been installed on the Java system.

For servlets to make HTTPS connections, the Web container hosting the servlet should have the JSSE API (see Section 13.4.1 on page 460) installed and available in the Java runtime class path (see Section 7.2.2 on page 207) with the necessary authorizations granted. Additionally, a JSSE provider must be installed and configured for use by the J2EE programs that need to establish SSL connections (see Section Listing 11.1. on page 384 and Section 11.1.3.3 on page 387).

After JSSE is available to be used by the Web container, the system property java.protocol.handler.pkgs may be set to an SSL protocol handler class. This can be done either statically or programmatically. A static configuration usually involves editing a property file on the WAS. A programmatic configuration requires making a System.setProperty() method call. The following line of code shows how to set the IBM SSL protocol handler programmatically:

 System.setProperty("java.protocol.handler.pkgs",    "com.ibm.net.ssl.internal.www.protocol"); 

As we saw in Section 4.9 on page 145, Web components cannot expect to be allowed to set system properties; they can expect to be allowed only to read them. Also, note that multiple Web components may coexist within the same JVM. Therefore, setting a protocol handler will affect other Web components and may conflict with the provider that the container will want to use. Therefore, setting a JVM-wide provider is not a good option.

By specifying the appropriate java.net.URLStreamHandler as the third parameter, Web components can provide the protocol handler programmatically when they construct the URL object. For example, the MalformedURLException will no longer be thrown, and the appropriate HTTPS protocol handler will be used for the connection when constructing an HTTPS URL object, as in the following line of code:

 URL url = new URL(null, "https://www.fabrikam456.com",    new com.ibm.net.ssl.internal.www.protocol.https.Handler()); 

When the URL object being constructed is intended to connect to the standard SSL port, 443, it is not necessary to specify the port number as part of the URL. However, if the servlet needs to connect to a nonstandard port ”for example, 9443 ”it is necessary to append the port number to the target URL, as shown in the following line of code:

 URL url = new URL(null, "https://www.fabrikam456.com:9443",    new com.ibm.net.ssl.internal.www.protocol.https.Handler()); 

If a URL refers to a resource hosted on a server that has an invalid or untrusted certificate, an attempt to retrieve the java.io.InputStream or the java.io.OutputStream from the associated java.net.URLConnection object will throw a javax.net.ssl.SSLException with the message untrusted server cert chain . The InputStream and OutputStream can be obtained by calling getInputStream() and getOutputStream() on the URLConnection object, respectively. However, if the server has a valid, trusted certificate, no exception will be thrown. The resultant URL object can be used to open the connection and get the InputStream or OutputStream , as shown next :

 URL url = new URL(null, "https://www.fabrikam456.com",    new com.ibm.net.ssl.internal.www.protocol.https.Handler()); URLConnection con = url.openConnection(); InputStream is = con.getInputStream(); OutputStream os = con.getOutputStream(); 

When a servlet connects to an external HTTP server, it considers the servlet as a client. If the external HTTP server requires its clients to present their certificates to perform client authentication, as discussed in Section 4.5.1.3 on page 120, the Web container hosting the servlet needs to be configured to connect using the appropriate client certificate.

Similar considerations apply when a servlet tries to connect to a server whose server certificate was issued by a nonstandard CA. In this case, if the server is considered trusted, the key store used by the Web container to establish SSL connections between the servlet and the external HTTP servers needs to be updated to include the certificate of the external server the servlet is trying to connect to.

4.10.2 Maintaining the State Securely

As we observed in Section 4.5.2 on page 123, HTTP is a stateless protocol. The way HTTP operates is that an HTTP client initiates an HTTP transaction by sending a request to an HTTP server: for example, it asks for a Web page. The server responds; after that, the HTTP transaction is automatically closed. That request has no relation to the next request, if any, the client sends.

The advantage of this approach is that it allows an HTTP server to serve multiple clients simultaneously , without incurring the overhead generated by keeping several sessions opened with all the clients that initiated a request. The negative implication is that information about the client, including authentication and personalization information, needs to be resubmitted with every request.

  • In the context of a password-protected session, a user would have to enter a valid user ID and password pair on every request.

  • In the context of an online store, the HTTP server cannot know whether the client has selected items to purchase.

  • In the context of an online newspaper that allows users to specify which types of articles they are most interested in, the HTTP server cannot establish whether the client has previously specified preferences.

Resubmitting this information with every request is considered user unfriendly and may also have negative security implications. A solution to this problem would be for the Web server to store the information gathered from all the clients on some permanent storage. However, this solution is considered too expensive if implemented on the server side, especially if the HTTP server is contacted by a large number of users.

The J2EE architecture supports two solutions to maintain session state: HTTP cookies, and HTTP and SSL sessions. The next two subsections examine how these two solutions work and their security implications in a J2EE environment.

4.10.2.1 HTTP Cookies

An HTTP cookie [5] is a piece of information passed between an HTTP client and server during an HTTP transaction. The cookie is stored on the client machine under the form of a text file and can be shared across multiple requests . For example, the server may store a customer number in a cookie and send it to the client. On subsequent requests, the client will include the current value of that cookie as part of the requests. On receiving a request, the HTTP server extracts the value from the cookie and uses it to identify the session and process the request based on that information.

[5] See RFC 2109 at http://www.ietf.org/rfc/rfc2109.txt.

As part of a well-defined HTTP header, a cookie flows over the network in cleartext. Therefore, eavesdroppers can get at its value easily. When carrying sensitive information, a cookie should be set to be valid for a limited time period and be restricted to flow only over SSL connections. Cookies can be further restricted by taking advantage of their Domain and Path attributes.

  • The Domain attribute of a cookie specifies the domain for which the cookie is valid.

  • The Path attribute of a cookie specifies the subset of URLs to which the cookie applies.

Servlets can generate secure cookies, store information in them, and retrieve their contents on subsequent client requests by using the javax.servlet.http.Cookie class offered by the Java Servlet API:

  1. A Cookie object is created by passing cookie name and value String s to the Cookie constructor, as shown in the following line of code:

     Cookie cookie = new Cookie("Account Number", "1234-5678"); 
  2. A Cookie object can be made secure , which means that its Secure attribute is set. This is an indication for the client that the cookie should be sent back to the server using only a secure protocol, such as HTTPS or SSL. The line of code to make a Cookie object secure is shown next:

     cookie.setSecure(); 
  3. For increased security, a cookie can be made nonpersistent. This is an indication for the client ”typically, a Web browser ”that the cookie should not be permanently stored, and should instead be deleted when the client program exits. To make a cookie nonpersistent, a servlet can pass a negative int value to the setMaxAge() method on the Cookie object, as in the following line of code:

     cookie.setMaxAge(-1); 
  4. A servlet can send a cookie to a client by passing a Cookie object to the addCookie() method of an HttpServletResponse , as shown next:

     response.addCookie(cookie); 

    This method call adds fields to HTTP response headers to send cookies to the Web browser, one at a time. A Web browser is expected to support 20 cookies for each Web server, 300 cookies total, and may limit cookie size to 4 K each.

  5. A Web browser returns cookies to the servlet by adding fields to the HTTP request headers. A servlet can retrieve cookies from a client request in the form of a Cookie array by using the getCookies() method on an HttpServletRequest object.

     Cookie[] cookies = request.getCookies(); 
4.10.2.2 HTTP and SSL Sessions

HTTP cookies have inherent limited storage capabilities. Another disadvantage is that managing cookies must be handled within the application code. In order to abstract the notion of a session and related state, J2EE supports the notion of an HTTP session, represented as a javax.servlet.http.HttpSession object.

Servlets can create an HttpSession object associated with an HTTP request. Any information that needs to be associated with the request can be stored in the HttpSession object. For example, in our travel agency scenario, a customer's current selection of itinerary can be stored in an HttpSession object. Subsequent requests are processed without retrieving all the customer information from the back-end system. Instead, such information is retrieved from the associated HttpSession object. In scenarios like this, an HttpSession is associated with an identifier, jsessionid , that is part of the request. The identifier's value is exchanged either via a cookie or through URL rewriting.

In addition to these mechanisms, WASs support sessions by using an SSL session ID as the identifier for an HTTP session. Even though using SSL session IDs tightly links a request to its underlying transport security, this option is not always possible. One reason is that, as we observed in Section 4.5.1.3 on page 120, multiple HTTP servers might form the end point of an SSL handshake, and they may not always have access to the SSL session ID information. Another reason is that SSL sessions may be renegotiated periodically between HTTP clients and servers, resulting in a change of the session ID and hence the loss of HTTP session information.

If HTTP session identification is to be maintained through cookies, the Deployer must ensure that they are tranported only over SSL, to prevent eavesdropping and tampering. This helps prevent replay attacks [6] when obtaining the session ID can lead to access to the session itself, including the session information and application state.

[6] A replay attack consists of intercepting and recording messages in order to send them out later to a recipient unaware that the message is no longer legitimate . A replay attack is a type of denial-of-service attack (see page 237 and Section 7.4.4.1 on page 245).

Because HTTPSession objects may carry reference to sensitive information, it is also wise to choose a short timeout for the underlying HTTP sessions. If these session identifiers can be obtained by an untrusted third party, setting a small timeout will reduce the time window within which attacks may be possible. The timeout can be specified in a Web application's deployment descriptor and is specified in whole minutes. Listing 4.20 shows an example of setting a 30-minute window for an HTTP session.

Listing 4.20. Setting an HTTP Session Timeout
 <web-app>    <session-config>       <session-timeout>30</session-timeout>    </session-config> </web-app> 

4.10.3 Pre- and Post-Servlet Processing

A common pattern within Web applications is to perform some actions before and/or after processing a servlet. One example is monitoring the number of failed login attempts and taking an action, such as locking the account, after a maximum number of login attempts is reached. However, J2EE does not require facilities for user and account management.

One approach to handling pre- and post-servlet processing is through the use of servlet filters. Filters are software components that perform filtering tasks on either the request to a resource ”a servlet or static content ”or on the response from a resource or both. They allow dynamic ” on-the-fly ”manipulation of HTTP header and payload information as it flows in and out of Web containers. The Java Servlet API provides the javax.servlet.Filter interface to represent filters. Filters are associated with a servlet or a URI and are invoked on the inbound and outbound call paths.

Multiple filters can be associated with a request by chaining the filters. The servlet being filtered becomes the final component in the chain. Each filter in the chain is given an opportunity to handle requests. In J2EE, filter chains are represented as javax.servlet.FilterChain objects.

The use of servlet filters is a programming pattern for using a standard API for plugging security services into applications. Examples include login filters to monitor number of login attempts, auditing filters to securely log request details, and encryption filters to encrypt or decrypt the messages that are exchanged with a servlet. Note that even though servlet filters use a standard API, they are considered to be application code. Therefore, they need to be packaged with the Web applications with which they are associated. Alternatively, a given set of filters for an environment may get explicitly associated with all Web applications.

Let us consider a simple scenario in which a certain set of users must be prevented from logging in. A servlet filter can be designed to check whether a user attempting to log in is on this revocation list. The skeleton code in Listing 4.21 can be customized to address the requirements as appropriate ”for example, to obtain the revocation list from a database, LDAP directory, and so on.

Listing 4.21. CheckUserStatus.java
 import java.util.ArrayList; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /**  * A servlet filter that checks if a user trying to login  * is in a revocation list.  */ public class CheckUserStatus implements Filter {    protected FilterConfig filterConfig;    private java.util.List revocationList;    /**     * This method is called when the Filter is     * instantiated. This Filter is instantiated the first     * time j_security_check is invoked for the application,     * that is when a protected servlet in the application     * is accessed.     *     * @param filterConfig a FilterConfig object used by a     *        servlet container to pass information to the     *        filter during initialization.     * @throws ServletException if an exception has occurred     *        that interferes with the Filter's normal     *        operations.     */    public void init(FilterConfig filterConfig)       throws ServletException    {       this.filterConfig = filterConfig;       // Obtain the user revocation list.       revocationList = new java.util.ArrayList();       obtainRevocationList(revocationList);    }    /**     * This method is called when the Filter is taken out of     * service. This method is only called once all threads     * within the Filter's doFilter() method have exited or     * after a timeout period has passed. After the Web     * container calls this method, it will not call the     * doFilter() method again on this instance of the     * Filter.  This method gives the Filter an opportunity     * to clean up any resources that are being held. In     * particular, it cleans up the FilterConfig and the     * revocation list held by this instance of the Filter.     */    public void destroy()    {       filterConfig = null;       revocationList = null;    }    /**     * This method is called before the servlet that this     * Filter is mapped to is invoked. Since this Filter is     * mapped to j_security_check, this method is called     * before the j_security_check action is posted.     * The doFilter() method of the Filter is called by the     * container each time a request/response pair is passed     * through the chain due to a client request for a     * resource at the end of the chain. The FilterChain     * passed in to this method allows the Filter to pass on     * the request and response to the next entity in the     * chain.     *        * @param request a ServletRequest object representing     *        a request to the servlet associated with this     *        Filter.     * @param response a ServletResponse object representing     *        a response sent to the servlet associated with     *        this Filter.     * @param chain a FilterChain object representing the     *        invocation chain of a filtered request for a     *        resource. This FilterChain is used to invoke     *        the next filter in the chain, or if the     *        calling filter is the last filter in the     *        chain, to invoke the rosource at the end of     *        the chain.     * @throws IOException if an I/O error has occurred.     * @throws ServletException if an error has occurred     *        that interferes with the normal operation of     *        this Filter.     */    public void doFilter(ServletRequest request,       ServletResponse response, FilterChain chain)       throws IOException, ServletException    {       HttpServletRequest req =          (HttpServletRequest) request;       HttpServletResponse res =          (HttpServletResponse) response;       // Check if the user can be allowed to access the       // associated servlet before the authentication       // takes place.       // Get the user ID.       String userName = req.getParameter("j_username");       // Send error message if the user is among the set       // of users who are revoked of their access       // privileges.       if (revocationList.contains(userName))       {          res.sendError             (HttpServletResponse.SC_UNAUTHORIZED);          return;       }       // Call next filter in the chain. Let       // j_security_check authenticate user.       chain.doFilter(request, response);    }    /**     * Updates the list of users who are revoked of their     * access privileges.     *     * @param userList an ArrayList containing the users     *        who have been revoked of their access     *        privileges.     */    private void obtainRevocationlist(ArrayList userList)    {       // In this sample, three users are hardcoded as       // revoked. They are hardcoded to illustrate the       // concepts. Replace this method implementation       // using other means to obtain the revocation list       // (for example, read it from file, obtain it from       // a database, get it from an LDAP directory, etc.).       userList.add("bob");       userList.add("user123");       userList.add("empl234");    } } 
 <  Day Day Up  >  


Enterprise Java Security. Building Secure J2EE Applications
Enterprise Javaв„ў Security: Building Secure J2EEв„ў Applications
ISBN: 0321118898
EAN: 2147483647
Year: 2004
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net