Core Security Patterns: Best Practices and Strategies for J2EE, Web Services, and Identity Management
J2EE Component/Tier-Level Security
J2EE-based applications and Web services applications are made up of discrete components that build a multi-tier enterprise application. Although these components run in different component containers, the J2EE specification mandates that J2EE server vendors deliver mechanisms for securing each tier and its associated components, clients, and users. In an end-to-end J2EE application practice, JSPs and Servlets form the presentation-tier components, EJBs will form the business logic behind presentation components, and connectors and other drivers will form the integration-tier components. When a Web component interacts with a client user, it collects the security credentials about the user for authentication against the J2EE server's security infrastructure. After identifying the user, it forwards the authenticated identity to determine the access to the required components. When the authenticated identity attempts to carry out that particular operation, the container first determines whether the identity has the privileges to access or deny the operation based on the assigned role and its access rights. So in J2EE security practice, before implementing the component-level security, it is crucial to understand the mechanisms that contribute to the access control and how to represent users, groups, roles, and realms. This helps to achieve the applied J2EE security in the operational environment with an adequate degree of authentication and authorization that addresses the security requirements of the different component tiers and their users. Users, Groups, Roles, and Realms
In a J2EE environment, security privileges and access control rights are defined by linking users, groups, roles, and realms to JSP/Servlet/EJB methods, URLs, or Web-service endpoints. This allows applying security privileges either at the application level, by mapping privileges to deployed components and their implemented methods, or at the system environment level, by mapping privileges to the operational environment and services. User: Represents the end user of the application or a software client or service that interacts with a J2EE-based application environment. As a result of authentication, a user is assigned with a Principal. Users may represent a group associated with security roles, or they can be directly associated with roles. Group: Represents a set of authenticated users, categorized based on logical characteristics. Groups allow addressing a number of users who assume a role or typically functions as one entity. Roles: Represents security permissions or privileges granted to users or groups to access or restrict a particular set of resources or operations. Roles are represented dynamically to users and groups based on conditions, and roles can be scoped to represent a single application or multiple applications and their underlying resources. Realms: Represents a collection of users, groups, and roles used for protecting a single application or multiple applications and their underlying resources. Realms also provide mechanisms for implementing security constraints to protect applications and resources by integrating users, groups, and roles. In a J2EE environment, realms allow security management for applications and resources by mapping security mechanisms to applications and users, mapping one or more users to groups, and mapping one or more groups or users to roles. J2EE server vendors provide support for configuring realms using user information directories such as LDAP, RDBMS, and custom file formats. Using realms also allows implementing authentication and authorization based on user-specific information and the user's mapping role. Configuring a realm is vendor-specific; refer to the J2EE vendor administration guide for configuration procedures. Web- or Presentation-Tier Security
In a J2EE environment, the Web tier represents the presentation components, which interact between the end user Web clients and the underlying application's business logic. The Web-tier components generally consist of JSPs, Servlets, Java Applets, Static HTML files, and associated helper classes that are packaged and deployed as a single Web application or as multiple application components running in a J2EE application server or a Servlet engine. A Web application file is packaged as a (.war) file containing all of the class files and resources for the Web application, along with an XML-based deployment descriptor file that contains the configuration information for the application. The Web tier typically produces content to its end users, which can be of any content type, including HTML, XML, Image, or Sound, and more importantly, the Web tier delivers the content to a Web browser or a device that has the ability to access the application. While business logic is often implemented as Enterprise Java Beans (EJB), it can also be implemented entirely within the Web tier using Web components such as JSPs, Servlets, and JSF, along with helper classes. The Web container provides multilayer security mechanisms for the Web-tier components to enforce security and controlled access to operations and their underlying resources. The security features include authentication, authorization, user login mechanisms, secure session handling, securing the client interactions, transport-layer security, single sign-on access for integrating multiple applications, and so forth. Let's take a closer look at these features in order to understand how they contribute to the end-to-end security of a J2EE-based application. Web-Tier Authentication Mechanisms
To protect and control access to Web applications, the Web container facilitates authentication mechanisms that can be configured for a Web application prior to its deployment. When an unauthenticated user attempts to access a protected Web application, the Web container will prompt the user to authenticate with the Web container using the configured authentication mechanisms. The user's request will not be accepted by the Web container until the user has been authenticated to the Web container with its required credentials and identified to be one of the users with granted permission to access the application and its resources. Most J2EE platform vendors provide the Web container with the following authentication mechanisms: HTTP Basic Authentication
The Web container authenticates the requesting identity using username and password information. When a Web application is configured with Basic Authentication, the Web container requests the interacting user's browser to capture the username and password using a dialog and then send those values to the server as part of the request. To secure a Web application using HTTP Basic Authentication login, the login-config element in the Web component deployment descriptor is configured. The login-config element includes auth-method and realm-name sub-elements, which contain the element values BASIC and the realm name to be used for login. Example 5-4 is a code snippet of the deployment descriptor illustrating the declaration of HTTP Basic Authentication. Example 5-4. Deployment descriptor for setting HTTP basic authentication
<web-app> . . . security-constraint>. . .</security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>myrealm</realm-name> </login-config> . . . </web-app>
Realm name applies only when the authentication method is BASIC. It provides the name of the security realm in which the user is required to log in and authenticate. Form-Based Authentication
This allows specifying a custom login interface using a JSP/Servlet/HTML page to authenticate a user who is trying to access a protected Web application. It also allows configuring a custom login error page to display an invalid authentication request. To set up Form-based Authentication, it is necessary to configure login-config and form-login-config elements in the Web component deployment descriptor. The form-login-config element includes form-login-page and form-error-page sub-elements, which contain the element values referring to the URL pages to be displayed for login and error. Example 5-5 is a code snippet of the deployment descriptor illustrating the declaration of Form-based Authentication. Example 5-5. Deployment descriptor for setting form-based authentication
<web-app> . . . <security-constraint>. . .</security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>myLogin.jsp</form-login-page> <form-error-page>myError.jsp</form-error-page> </form-login-config> </login-config> . . . </web-app>
In addition to configuring the Web deployment descriptor, the JSP and Servlet specifications mandate that the custom login interface (using JSP, Servlet, or HTML) be implemented with the special action attribute j_security_check as well as the name attributes j_username (username field) and j_password (password field) when obtaining the username and password inputs. Example 5-6 is a JSP example of myLogin.jsp, illustrating a Form-based Authentication login page. Example 5-6. Form-based authenticationsample login page
<%@ page contentType="test/html" %> <html><body> <head> <title>Form based login page</title> </head> <h2>Enter your user name and password:</h2> <p> <form method="POST" action="j_security_check"> <table border=1> <tr> <td>Username:</td> <td><input type="text" name="j_username"></td> </tr> <tr> <td>Password:</td> <td><input type="password" name="j_password"></td> </tr> <tr> <td colspan=2 align=right> <input type=submit value="Submit"></td> </tr> </table> </form> </body></html>
To display login failures and error conditions, it is also necessary to define an error page. Example 5-7 is a JSP example of myError.jsp that illustrates an error page that will display after an authentication request is made by a user who is not authorized to access the protected Web application. Example 5-7. Error page to display after an authentication failure
<%@ page contentType="test/html" %> <html> <body> <h1> Error Invalid username or password</h1> <p>To retry, Try <a href="/myLogin.jsp">Login</a> or <a href="/logout.jsp">Logout</a> </p> </body> </html>
Form-based Authentication mechanisms can also be used for GUI clients, including Swing- and AWT-based applet clients. The implementation steps are the same, except the Swing- or AWT-based applets are required to use a Client application component that provides Form-based Authentication. In the case of rich clients using RMI/IIOP communication, the client may choose to use JNDI lookup for creating an InitialContext and then do authentication by passing the username and password information. Alternatively, use JAAS authentication and custom CallbackHandler for login, and then use the Security.runAs() method inside the Swing event thread and its children. HTTP Basic or Form-Based Authentication over SSL (HTTPS)
Both HTTP Basic and Form-based authentication use Base64 encoding, which is generally considered insecure because it exposes username and password information if someone intercepts the communication and decodes them. HTTP Basic and Form-based Authentication over SSL (HTTPS) is considered the best approach, because they ensure secure communication using digital certificates (encrypting the data sent and then decrypting the data upon receipt). HTTPS ensures a secure communication channel using the SSL/TLS protocol before initiating the HTTP authentication request. This allows establishing confidentiality and data integrity during communication using public-key certificates and SSL/TLS configuration done at the J2EE server or Web container provider. To configure HTTP Basic or Form-based Authentication over SSL, it is necessary to use the transport-guarantee element in the Web deployment descriptor. To configure HTTP Basic or Form-based Authentication over SSL in the transport-guarantee element, specify the value as CONFIDENTIAL when the Web application requires that the data to be transmitted is secured from viewing during transmission, or specify INTEGRAL as the value when the Web application requires that the data be sent between client and server in such a way that it cannot be tampered with during transit. Example 5-8 is an example Web deployment descriptor configuring HTTPS for Form-based Authentication. Example 5-8. Deployment descriptor for HTTPS in form-based authentication
<web-app> . . . <security-constraint> . . . <user-data-constraint> <description> Secure transmission using HTTP/SSL. </description> <transport-guarantee> CONFIDENTIAL </transport-guarantee> </user-data-constraint> . . . </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/myLogin.jsp</form-login-page> <form-error-page>/myError.jsp</form-error-page> </form-login-config> </login-config> . . . </web-app> Client-Certificate or Mutual Authentication
This allows configuring the Web container or Servlet engine to accept HTTP requests using bidirectional SSL and authenticate client users' public-key certificates issued by a trusted certificate authority (CA). This facilitates a strong-authentication mechanism whereby both the client and server use their digital certificates to prove their identities over a bidirectional SSL connection. To secure a Web application using Client-Certificate or Mutual Authentication-based login access, configure the login-config element in the Web component deployment descriptor. The login-config element includes auth-method, which contains the element value CLIENT-CERT (see Example 5-9). Example 5-9. Deployment descriptor for client-certificate authentication
<web-app> . . . security-constraint>. . .</security-constraint> <login-config> <auth-method>CLIENT-CERT</auth-method> </login-config> . . . </web-app> Digest Authentication
This allows a Web client to authenticate a Web container by sending a message digest along with its HTTP request message. Digest-based authentication is also deemed to be insecure because an attacker can intercept and capture the hashed password and resend it as a replay attack. Using digests over SSL should be considered so that the communication remains secure and tamperproof. Digest authentication is quite similar to HTTP Basic Authentication, except that requesting the user's password is represented as a scrambled text using a one-way hash algorithm (message digest). To secure a Web application using Digest Authentication-based login access, configure the login-config element in the Web component deployment descriptor. The login-config element includes auth-method, which contains the element value DIGEST, which tells the client to transmit the username and password encrypted using a message digest (see Example 5-10). Example 5-10. Deployment descriptor for digest authentication
<web-app> . . . security-constraint>. . .</security-constraint> <login-config> <auth-method>DIGEST</auth-method> </login-config> . . . </web-app> It is very important to note that very few Web browsers support Digest Authentication and that the JSP and Servlet specifications do not mandate this method either. Using JAAS for Web-Tier Authentication
The introduction of JAAS to the J2EE platform allows enforcing authentication and access controls based on user identity in a Web container and its components. Using JAAS facilitates using a pluggable login module and ensures that applications remain independent of their authentication mechanisms. This allows the creation of custom login modules for Web applications that support multiple client types and devices and the use of authentication interfaces using smart card or biometric sensors. It also permits use of custom user repositories based on Flat-file, LDAP, NT Realm, RDBMS, and so forth. JAAS also provides a single sign-on security architecture solution for handling multiple Web applications with a unified login access to authenticate the identity and to determine its user access privileges. Most J2EE vendors and Servlet container providers implement support for JAAS-based authentication and authorization mechanisms. To implement JAAS-based authentication and authorization for Web applications, it is necessary to use JAAS LoginModules built using JAAS APIs. In a J2EE environment, JAAS LoginModules are usually configured as a Realm. Using the JAAS LoginModule, the Realm governs the authentication process of the application by mapping the user, group, security role, security policy, and other credential information. To learn more about JAAS APIs and the programming model, refer to "Java Authentication and Authorization Service" in Chapter 4, "Java Extensible Security Architecture and APIs." For more information about how to plug in JAAS providers in a J2EE environment, follow your J2EE vendor-provided administration guide procedure for installing a JAAS provider. Single Sign-On Authentication for Web Applications
Single sign-on authentication in the Web Tier allows multiple applications that require the same user sign-on information to share this information among themselves rather than requiring the user to sign on separately for each application. When a user first accesses an application, the person is required to log in once. When needed, the authentication information is propagated to all other involved applications. Once authenticated, the roles associated with this user are used for access-control decisions across all associated Web applications; the user is not asked to authenticate to each application individually. When the user logs out of one Web application (for example, by invalidating or timing out the corresponding session if Form-based login is used), the user's sessions in all Web applications are invalidated. Any subsequent attempt to access a protected resource in any application requires the user to reauthenticate. Traditionally, the single sign-on feature for Web applications utilizes HTTP cookies (discussed later in this chapter) to transmit a token that associates each request with the saved user identity, so single sign-on can only be used in client environments that support cookies. Using JAAS also allows enabling single sign-on authentication for Web applications. When multiple Web applications are deployed on a J2EE application server, usually each application authenticates its client user by using a user repository such as LDAP or RDBMS. To establish single sign-on, each application will define its own JAAS LoginModule for its authentication provider. All login modules are stacked together and configured using a JAAS configuration file. From a programming standpoint, JAAS LoginContext executes all configured authentication provider LoginModule instances and is responsible for managing those configured authentication providers. Once the caller has instantiated a LoginContext, it invokes the login method to authenticate a Subject. This login method iterates through all the configured LoginModules and invokes the login method for each LoginModule assigned to the application. This allows determination of the overall authentication result by combining the successful login results returned from each login module. Each LoginModule maintains the state of remembering whether or not its login or commit method previously succeeded or failed. To establish single sign-on, JAAS uses the shared-state mechanism, which allows passing the authentication information between login modules and results in a unified sign-on for the user, who now has access to all configured applications. To log out, the caller client invokes the logout method, which in turn invokes the logout method of the LoginModules configured for the applications. Refer to the section "Java Authentication and Authorization Service" in Chapter 4, "Java Extensible Security Architecture and APIs," for information about the JAAS programming and login module configuration. Agent-based Authentication for Web-Tier Applications
Most J2EE application server vendors and Web containers provide authentication support via agents from third-party security or identity infrastructure providers. The use of these security or identity provider infrastructures allows enforcement of authentication and access control policies regardless of whether the caller client is a browser, device, or Java/Non-Java application. In addition, the application no longer needs to use its own container-based mechanisms to perform authentication. This also adds value to the application by making it independent of the type of authentication mechanism used. This means that the authentication mechanism can be changed without affecting the Web application. Figure 5-4 represents an agent-based authentication model for securing Web-tier applications. Figure 5-4. Agent-based authentication
In a typical usage scenario, the Web agent installed in the Web server intercepts the caller's request before forwarding it to a J2EE server or its Web container. After interception, it verifies the caller's request for authentication credentials. If there are no authentication credentials present or the existing authentication credentials are found to be insufficient, then the security provider's authentication service will present a login page or a login challenge window. The login page prompts the user for credentials such as username and password. After proper authentication, the agent examines all the roles assigned to the user. Based on the policies assigned to the user, the client will be either allowed or denied access to the Web application or its protected URL. HTTP Session Tracking Using Cookies and URL Rewriting
An HTTP session (Session) is a series of user requests from a Web browser client during a definite period of time. An HTTP session usually corresponds to one user who accesses a Web application through a Web browser. Using an HTTP session allows you to identify and track users and maintain their Web application requests as a conversational state. The Web container uses Session objects to maintain the user-specific information from user requests over JSPs, Servlets, and even from HTML pages. An example would be a Shopping Cart application saving the state of a user's shopping cart transactions across requests. To handle HTTP sessions, the Web browser-based clients are usually required to support cookies or URL rewriting mechanisms for maintaining the client session state. With traditional Java clients, managing session state is a responsibility of the client applications because they can cache and manipulate substantial amounts of session state in memory. Session state maintenance has an enormous impact on application security, performance, availability, and scalability. When designing a Web application, it is quite important to identify the risks and associated mitigation options in order to manage the state and effectively track the current saved state. From a Web-tier security infrastructure standpoint, HTTP sessions play a vital role in maintaining security-specific information in the user's session state and in propagating security context in Web-based single sign-on scenarios. It is necessary to maintain a relatively high level of control and tight security over session information in both server and client environments. In J2EE application servers, the Web-tier HTTP sessions can be tracked, maintained, and managed via cookies, URL rewriting, and hidden fields in HTML forms or with a combination of cookies and/or URL rewriting. In the case of cookie-disabled Web browsers, it is the responsibility of the Web application or the server infrastructure to enable session tracking via URL rewriting. With URL rewriting, the client appends the additional data to the end of each URL to identify the session, and the server associates the data to the stored session. To ensure session information security, make sure the cookies are encrypted and URLs are encoded in case of URL rewriting. Refer to the J2EE vendor security administration guide for configuration procedures. Using HTTP sessions in Web applications is relatively simple. It involves looking up attributes associated with an HTTP request, creating a session object, looking up and storing user-specific information with a session, and terminating completed or abandoned sessions. Creating and Assessing an HTTP Session
In a J2EE environment, Sessions are represented using javax.servlet.http.HttpSession objects that usually reside in the Web container. HTTPSession objects are associated with a user through cookies or URL rewriting or a combination of both. The Web container uses the HTTPSession interface to create an HTTP session between a Web browser client and a Web server. The created session usually persists in the Web container for the specific period of time defined in the Web application configuration. It also allows viewing and manipulating information about a user request, such as user's session identifier, session state, session created time, and last accessed time. It also allows binding user-specific objects to sessions and persisting them across multiple connections. To create a new HTTP session or to obtain access to an existing session, use the HttpServletRequest method's getSession() method, as shown in Example 5-11. Example 5-11. Creating an HTTP session
HttpSession mySession = request.getSession(); The getSession() method returns the valid session object associated with the user's HTTP request, which is identified in the session cookie that is encapsulated in the request object. Calling the method with no arguments creates a new HTTP session if one does not already exist. Calling the method with a Boolean argument creates a session only if the argument is true. Example 5-12 is a snippet showing a doPost() method from a servlet that performs the servlet's functions if the HTTP session is present. This means that the false parameter to getSession() prevents the servlet from creating a new session if one does not already exist, as shown in Example 5-12 Servlet showing how to prevent creating new session if one exists. Example 5-12. Servlet showing how to prevent creating new session if one exists
public void doPost (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if ( HttpSession session = req.getSession(false) ) { // HTTP session present, continuing // servlet operations } else // HTTP session not available, // return an error page } } Examining HTTP Session Properties
Once an HTTP session is created, we can set session attributes by name. The session attributes are stored as state information in the request related to the session. This can be examined by using the public methods in the HTTPSession interface. Example 5-13 would obtain the session attributes stored by a Web application. Example 5-13. Obtaining session attributes from HTTP session
HttpSession mySession = request.getSession(); // To obtain the Session ID String myName = mySession.getAttribute("name"); Invalidating an HTTP Session
Once the client interaction is completed, it is the responsibility of the Web application to clean up the existing HTTP session state and to remove any client-specific session information. Leaving stale sessions on the server often leads to security breaches involving session hijacking, client-side trojans, and eavesdropping on subsequent sessions. To invalidate an HTTP session on the server side, use the invalidate() method. Example 5-14 would invalidate a session stored by a Web application. Example 5-14. Invalidating an HTTP session
HttpSession mySession = request.getSession(); // . . . // Use HTTP Session attributes // Finally invalidate the session mySession.invalidate(); HTTP Session Timeout
In the case of Web applications with a very large number of users, the server would be overburdened with the task of keeping a huge number of session objects alive. This would usually tax system resources in terms of memory, storage, and CPU capacity, thus reducing their efficiency. It is important to track user sessions after a period of inactivity, because there is no option for an HTTP client to signal a server that it no longer needs a session. So session timeout becomes a mandatory event, and each session has an associated timeout so that its resources can be reclaimed. From a security standpoint, if the user is missing after a period of user inactivity, the session timeout must automatically occur and the missing user needs to be logged out. The user can access the requested resource only after providing new credentials. To enable the HTTP session timeout, the Web application is required to set a default session timeout period in the Web application deployment descriptor (web.xml), as shown in Example 5-15. Example 5-15. Deployment descriptor setting for default session timeout
<session-config> <session-timeout>30</session-timeout> <session-config>
With this setting, the user's session will automatically be deactivated after 30 minutes of inactivity. The timeout period can also be controlled by using HTTPSession getMaxInactiveInterval and setMaxInactiveInterval methods, which allows to programmatically specify timeout in seconds. The snippet in Example 5-16 will invalidate a user's session after a period of inactivity in timeoutInSeconds seconds. Example 5-16. Session invalidation after inactivity
session.setmaxinactiveinternal(int timeOutInSeconds);
Web-Tier Authorization Mechanisms
The J2EE Web container adopts role-based authorization mechanisms to restrict access control for Web components and their associated resources. When a Web-tier client initiates a request with a successful authentication, the Web container verifies the security attributes from the client's credentials and identifies the access control rules for the target resource. If the rules are satisfied, the container allows the caller to access the resource; otherwise, it denies the request. If the protected Web resource is accessed by an unauthenticated user, the Web container will direct the application to prompt the user to request the authentication credentials. The Web container will only allow the request after the user has been authenticated with appropriate credentials that grant permission to access the requested resources. Security Context and Access Control
Once the Web container performs the authentication and obtains the security credentials of an authenticated principal, it maintains them as part of the user session. This information is usually referred to as a security context. The security context will be used and enforced whenever the user attempts to access a protected Web resource. The container uses the roles known to be associated with the authenticated user in conjunction with the roles authorized to access the component, as defined in the Web deployment descriptor, to either permit access or deny it. For example, the container will allow an authenticated user "securityguy," who belongs to the "admin" role, to access a Web application component with a deployment descriptor setting that specifies "admin," which defines the role to authorize access to the particular resource. The Web-tier authorization follows the general J2EE security mechanisms using both declarative and programmatic security models. Declaring Security and Authorization Constraints
In Web application components, using a <security-constraint> in the Web application deployment descriptor performs authorization and enforces role-based access control. The <security-constraint> and its <auth-constraint> sub-element determines who is authorized to access protected Web resources that include Web components such as JSPs, Servlets, URL patterns, and HTTP methods. The security constraints work only on the original Web application request URI initiated by the caller and not on calls made from the service methods via a RequestDispatcher (which include <jsp:include> and <jsp:forward>). This means that inside the application, the application has access control over all required resources, and it would not forward a user's request to access a resource unless the requesting user had privileges to access them. In addition, after authentication, the container retrieves the specified security roles for the authenticated user and checks to see if the user belongs to one of the roles defined in the <auth-constraint> tag of the Web deployment descriptor. If the user does not belong to the specified roles for the Web resource, the request is terminated with an error message. The Web deployment descriptor code snippet in Example 5-17 shows the representation of security and authorization constraints (web.xml). Example 5-17. Representation of security and authorization constraints
<web-app> . . . <security-constraint> <web-resource-collection> <web-resource-name> My Secure Resource </web-resource-name> <!Define context-relative URL(s) to be secured --> <url-pattern> /export/home/jsp/security/mysecure-resource/* </url-pattern> <!Define the HTTP methods, to be protected --> <http-method>DELETE</http-method> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>PUT</http-method> </web-resource-collection> <!Define the roles that may access this resource --> <auth-constraint> <role-name>authors</role-name> <role-name>readers</role-name> <role-name>publishers</role-name> </auth-constraint> </security-constraint> . . . </web-app>
Web-Tier Programmatic Authorization
Programmatic authorization is used to enforce access control mechanisms such as dynamic access rules within an application, multi-role access, and content-level authorization. It is also used when the access-control policies using declarative options are not sufficient to express the Web application security requirements. In the Web Tier, the programmatic authorization can be done using the following methods of the HttpServletRequest interface.
|
Категории