Web applications often require that certain parts of the system be secured. Some security requirements can be satisfied with standard security mechanisms, while others call for a customized approach. Sometimes, as a developer, you may need to use a combination of these two techniques. This article helps you examine the issues and techniques. It is excerpted from chapter 19 of the book The Complete Reference: Struts, written by James Holmes (McGraw-Hill/Osborne, 2004; ISBN: 0072231319 ).
Most Web applications require certain aspects of the system to be secured in some manner. Security requirements are often specified at both the system and functional levels. System requirements may dictate, for example, that entry of sensitive information should be performed over a secure HTTP connection (HTTPS). On a higher level, functional requirements may dictate that only users with administrative privileges can access certain pages and menu items. From a developerís perspective, the critical task is to identify which of the requirements can be satisfied using standard security mechanisms, and which requirements require a customized security solution. Quite often, security requirements dictate some sort of customization. In some cases, you can use a combination of standard security mechanisms and customization to achieve the desired security policy.
---------Levels of Security
Security is a fairly broad topic and may encompass everything from encryption to personalization, depending on how "security" is defined. This chapter focuses on the levels of security that you can implement to secure your Struts applications, beginning in this section with an overview of the various security levels. That is followed by sections that look in depth at using container-managed security and application-managed security, the two primary ways to secure your Struts applications.
Transport-level security using HTTPS
Authentication and authorization
Role-based access control
Some aspects of personalization will also be covered, specifically some techniques for hiding or displaying content based on a userís authorization.
Providing Secure Communications
Data can be securely transmitted by using HTTP over Secure Socket Layer (referred to as HTTPS). HTTPS secures data by encrypting the protocol at the transport level. In other words, the entire HTTP conversation between the client browser and the Web server is encrypted. Struts applications, like most Web applications, can send data over HTTPS without modification.
HTTPS does impact performance, however. There is an order of magnitude of performance penalty when using HTTPS. To reduce the impact on performance, it is common for applications to switch the protocol between HTTP and HTTPS. The typical scenario uses the HTTPS protocol for application login and submission of sensitive data. Once the data is entered, the protocol is switched back to HTTP. While on the surface this seems like a good approach, it leaves open a serious security hole whereby the userís session can be hijacked. Sensitive user information, such as a credit card number, may be stored in that session. A network snoop could use the session ID to spoof a valid user session. Due to this risk, container-managed security does not support protocol switching. However, if you need protocol switching and can accept the security risks, there are mechanisms for doing so that integrate with Struts, as you will see in ďIntegrating Struts with SSL,Ē later in this chapter.
Authentication and Authorization
Authentication is the process of proving to an application that you are who you say you are. For Web applications, this process is most commonly associated with entering a username and password. If you are registered as a user of the application and you provide a valid password, the application allows access to privileged features of the application. In contrast, if you cannot provide valid credentials, you are allowed access only to the public areas of the site. In fact, many Web applications may only allow authenticated accessówith the only public page being the login screen. Authentication can be provided through custom coding for the application, or by using container-managed security services.
Authorization is how the application determines which aspects of the Web application you are allowed to access. Generally speaking, determining a userís authorization requires the user to first be authenticated. Once authenticated, application-provided or container-managed security can be used to determine a userís authorization.
Role-based Access Control
Role-based access control (RBAC) is a common scheme for implementing authorization. Users are assigned roles through a container-specific means. When a user is authenticated, the userís roles are associated with the HTTP request. Given this information, access to certain pages or user interface components can be allowed or disallowed based on the userís roles. In most cases, a user is allowed to have multiple roles. However, roles are typically flat; that is, there is no hierarchical relationship between roles.
Container- vs. Application-Managed Security
Servlet containers provide security as specified by the servlet specification. Container-managed security allows the developer to declaratively specify how authentication is to be performed and how authorization is to be granted. Container-managed security provides an easy, unobtrusive way of adding security to an application. This mechanism of implementing security provides the following benefits:
It is declarative. Authentication and authorization are specified in the web.xmlfile. Container-specific details, such as the security realm, typically are configured in server-specific XML configuration files.
It supports multiple authentication schemes, such as password authentication, FORM-based authentication, authentication using encrypted passwords, and authentication using client-side digital certificates.
Using container-specific security realms, user data can be provided by a variety of stores, including flat files, relational databases, and Lightweight Directory Access Protocol (LDAP) servers.
Redirects are handled automatically. In other words, the container determines when a user is accessing a protected URL, prompts for user credentials, and, if authenticated, redirects to the requested page. This is a powerful mechanism, particularly for applications that publish links to protected pages in e-mail communications.
Containers are, however, somewhat limiting because of the following:
The implementation of container-managed security varies by container. An application using container-managed security generally requires modification at some level when ported from one application server to another.
The login flow does not allow easy custom processing of login requests. In other words, additional processing cannot be performed in the authentication process.
Authorization can only use a flat, role-based approach. Access to Web pages cannot be granted based on multiple factors, for example, a managerial level and a department number.
FORM-based login forces a workflow that uses a separate page for login. This limits the flexibility of the application.
Container-managed authentication requires changes to the application serverís configuration that may not be allowed in a hosted environment.
These limitations can be overcome by using application-managed security. However, using application-managed security means that custom code must be designed and written. The decision of which approach to take should be driven by the requirements.
While container-managed security is simpler to implement, it does restrict the flexibility of your security policy. One containerís security implementation may be different from anotherís, making your application less portable. Also, container-managed security limits you to a specific login workflow that may not be what you want for your application.
Application-managed security, on the other hand, allows you to implement your security policy as needed at the price of requiring more custom code. Struts mitigates this problem by allowing for customized role processing via a custom request processor. Also, servlet filters can be used to apply across-the-board security policies. Cookies can be used to persist user login information between sessions. In addition, there are Struts extensions that permit finer-grained control of the use of HTTPS.
One last point: there is a somewhat hybrid approach that allows programmatic access to the methods that are usually only available when using container-managed security. This interesting mechanism will be covered later in the chapter, in the ďUsing Servlet Filters for SecurityĒ section.