In this sample chapter, Marty Hall discusses some of the major aspects of Web application security. He covers: authenticating users with HTML forms; using BASIC HTTP authentication; defining passwords in Tomcat, JRun, and ServletExec; designating protected resources with the security-constraintelement; using login-config to specify the authentication method; mandating the use of SSL; and configuring Tomcat to use SSL.

This sample chapter is excerpted from More Servlets and JavaServer Pages (JSP), by Marty Hall.

This chapter is from the book

Preventing unauthorized users from accessing sensitive data. This
process involves access restriction (identifying which resources need
protection and who should have access to them) and authentica-tion
(identifying users to determine if they are one of the authorized ones).
Simple authentication involves the user entering a username and password in an
HTML form or a dialog box; stronger authentica-tion involves the use of X509
certificates sent by the client to the server. This aspect applies to virtually
all secure applications. Even intranets at locations with physical access
controls usually require some sort of user authentication.

Preventing attackers from stealing network data while it is in
transit. This process involves the use of Secure Sockets Layer (SSL)
to encrypt the traffic between the browser and the server. This capa-bility is
generally reserved for particularly sensitive applications or particularly
sensitive pages within a larger application. After all, unless the attackers are
on your local subnet, it is exceedingly difficult for them to gain access to
your network traffic.

These two security aspects are mostly independent. The approaches to access
restriction are the same regardless of whether or not you use SSL. With the
excep-tion of client certificates (which apply only to SSL), the approaches to
authentication are also identical whether or not you use SSL.

Within the Web application framework, there are two general approaches to
this type of security:

Declarative security. With declarative security, the topic of this
chapter, none of the individual servlets or JSP pages need any security-aware
code. Instead, both of the major security aspects are handled by the
server.

To prevent unauthorized access, you use the Web application deployment
descriptor (web.xml) to declare that certain URLs need protection. You
also designate the authentication method that the server should use to identify
users. At request time, the server automatically prompts users for usernames and
passwords when they try to access restricted resources, automatically checks the
results against a predefined set of usernames and passwords, and automatically
keeps track of which users have previously been authenticated. This process is
completely transparent to the servlets and JSP pages.

To safeguard network data, you use the deployment descriptor to stipulate
that certain URLs should only be accessible with SSL. If users try to use a
regular HTTP connection to access one of these URLs, the server automatically
redirects them to the HTTPS (SSL) equivalent.

Programmatic security. With programmatic security, the topic of
the next chapter, protected servlets and JSP pages at least partially manage
their own security

To prevent unauthorized access, each servlet or JSP page must either
authenticate the user or verify that the user has been authenticated previously.

To safeguard network data, each servlet or JSP page has to check the network
protocol used to access it. If users try to use a regular HTTP connection to
access one of these URLs, the servlet or JSP page must manually redirect them to
the HTTPS (SSL) equivalent.

7.1 Form-Based Authentication

The most common type of declarative security uses regular HTML forms. The
developer uses the deployment descriptor to identify the protected resources and
to designate a page that has a form to collect usernames and passwords. A user
who attempts to access protected resources is redirected to the page containing
the form. When the form is submitted, the server checks the username and
password against a list of usernames, passwords and roles. If the login is
successful and the user belongs to a role that is permitted access to the page,
the user is granted access to the page originally requested. If the login is
unsuccessful, the user is sent to a designated error page. Behind the scenes,
the system uses some variation of session tracking to remember which users have
already been validated.

The whole process is automatic: redirection to the login page, checking of
user names and passwords, redirection back to the original resource, and
tracking of already authenticated users are all performed by the container
(server) in a manner that is completely transparent to the individual resources.
However, there is one major caveat: the servlet specification explicitly says
that form-based authentication is not guaranteed to work when the server is set
to perform session tracking based on URL rewriting instead of cookies (the
default session tracking mechanism).

Core Warning

Depending on your server, form-based authentication might fail when you use
URL rewriting as the basis of session tracking.

This type of access restriction and authentication is completely independent
of the protection of the network traffic. You can stipulate that SSL be used for
all, some, or none of your application; but doing so does not change the way you
restrict access or authenticate users. Nor does the use of SSL require your
individual servlets or JSP pages to participate in the security process;
redirection to the URL that uses SSL and encryption/decryption of the network
traffic are all performed by the server in a manner that is transparent to the
servlets and JSP pages.

Seven basic steps are required to set up your system to use this type of
form-based security. I'll summarize the steps here, then give details on
each step in the following subsections. All the steps except for the first are
standardized and portable across all servers that support version 2.2 or later
of the servlet API. Section 7.2 illustrates the concepts with a small
application.

Set up usernames, passwords, and roles. In this step, you
designate a list of users and associate each with a password and one or more
abstract roles (e.g., normal user or administrator). This is a completely
server-specific process. In general, you'll have to read your server's
documentation, but I'll summarize the process for Tomcat, JRun, and
ServletExec.

Tell the server that you are using form-based authentication.
Designate the locations of the login and login-failure page. This process
uses the web.xml login-configelement with an auth-methodsubelement of
FORMand a form-login-config subelement that gives the locations of the two
pages.

Create a login page. This page must have a form with an ACTIONof
j_security_check, a METHODof POST, a textfield named j_username, and a password
field named j_password.

Create a page to report failed login attempts. This page can
simply say something like "username and password not found" and
perhaps give a link back to the login page.

Specify which URLs should be password protected. For this step,
you use the security-constraintelement of web.xml. This element, in turn,
uses web-resource-collectionand auth-constraintsubelements. The first of these
(web-resource-collection) designates the URL patterns to which access should be
restricted, and the second (auth-constraint) specifies the abstract roles that
should have access to the resources at the given URLs.

Specify which URLs should be available only with SSL. If your
server supports SSL, you can stipulate that certain resources are available
only through encrypted HTTPS (SSL) connections. You use the
user-data-constraintsubelement of security-constraint for this purpose.

Turn off the invoker servlet. If your application restricts access
to servlets, the access restrictions are placed on the custom URLs that you
associate with the servlets. But, most servers have a default servlet URL:
http://host/webAppPrefix/servlet/ServletName. To prevent users from
bypassing the security settings, disable default servlet URLs of this form. To
disable these URLs, use the servlet-mappingele-ment with a url-patternsubelement
that designates a pattern of /servlet/*.

Details follow.

Setting Up Usernames, Passwords, and Roles

When a user attempts to access a protected resource in an application that is
using form-based authentication, the system uses an HTML form to ask for a
username and password, verifies that the password matches the user, determines
what abstract roles (regular user, administrator, executive, etc.) that user
belongs to, and sees whether any of those roles has permission to access the
resource. If so, the server redirects the user to the originally requested page.
If not, the server redirects the user to an error page.

The good news regarding this process is that the server (container) does a
lot of the work for you. The bad news is that the task of associating users with
passwords and logical roles is server specific. So, although you would not have
to change the web.xml file or any of the actual servlet and JSP code to
move a secure Web application from system to system, you would still have to
make custom changes on each system to set up the users and passwords.

In general, you will have to read your server's documentation to
determine how to assign passwords and role membership to users. However,
I'll summarize the process for Tomcat, JRun, and ServletExec.

Setting Passwords with Tomcat

Tomcat permits advanced developers to configure custom username and password
management schemes (e.g., by accessing a database, looking in the Unix
/etc/passwd file, checking the Windows NT/2000 User Account settings, or
making a Kerberos call). For details, see
http://jakarta.apache.org/tomcat/tomcat-4.0-doc/realm-howto.html.
However, this configuration is a lot of work, so Tomcat also provides a default
mechanism. With this mechanism, Tomcat stores usernames, passwords, and roles in
install_dir/ conf/tomcat-users.xml. This file should contain an XML
header followed by a tomcat-users element containing any number of user
elements. Each user element should have three attributes: name (the username),
password (the plain text password), and roles (a comma-separated list of logical
role names). Listing 7.1 presents a simple example that defines four users
(valjean, bishop, javert, thenardier), each of whom belongs to two logical
roles.

Note that the default Tomcat strategy of storing unencrypted passwords is a
poor one. First, an intruder that gains access to the server's file system
can obtain all the passwords. Second, even system administrators who are
authorized to access server resources should not be able to obtain user's
passwords. In fact, since many users reuse passwords on multiple systems,
passwords should never be stored in clear text. Instead, they should be
encrypted with an algorithm that cannot easily be reversed. Then, when a user
supplies a password, it is encrypted and the encrypted version is compared with
the stored encrypted password. Nevertheless, the default Tomcat approach makes
it easy to set up and test secure Web applications. Just keep in mind that for
real applications you'll want to replace the simple file-based password
scheme with something more robust (e.g., a database or a system call to Kerberos
or the Windows NT/2000 User Account system).

Setting Passwords with JRun

JRun, like Tomcat, permits developers to customize the username and password
management scheme. For details, see Chapter 39 (Web Application Authentication)
of
http://www.allaire.com/documents/jr31/devapp.pdf.
Also like Tomcat, JRun provides a file-based default mechanism. Unlike Tomcat,
however, JRun encrypts the passwords before storing them in the file. This
approach makes the default JRun strategy usable even in real-world applications.

With the default mechanism, JRun stores usernames, encrypted passwords, and
roles in install_dir/lib/users.properties. This file contains entries of
three types: user.username entries that associate a password with a user;
group.groupname entries that group users together; and
role.rolename entries that place users and/ or groups into logical roles.
Encrypted passwords can be obtained from an existing Unix-based password or
.htaccess file or by using the PropertyFileAuthentica-tion class supplied
with JRun. To use this class, temporarily set your CLASSPATH (not the
server's CLASSPATH) to include install_dir/lib/jrun.jar and
install_dir/lib/ ext/servlet.jar, change directory to
install_dir/lib, and add a user at a time with the -add flag, as below.
For real applications you would probably set up the server to automate this
process.

java allaire.jrun.security.PropertyFileAuthentication valjean grace

After adding the users, edit the file to assign the roles. Listing 7.2 shows
an example that sets up the same users, passwords, and roles as in the previous
Tomcat example (Listing 7.1).

Setting Passwords with ServletExec

The process of setting up usernames, passwords, and roles is particularly
simple with ServletExec. Simply open the administrator home page and select
Users within the Web Applications heading (Figure 71). From there, you can
interactively enter usernames, passwords, and roles (Figure 72). Voila!

With the free desktop debugger version, ServletExec stores the usernames and
passwords in plain text in install_dir/ServletExec Data/users.properties.
The passwords are encrypted in the deployment version.

Telling the Server You Are Using Form-Based Authentication; Designating
Locations of Login and Login-Failure Pages

You use the login-config element in the deployment descriptor
(web.xml) to control the authentication method. Recall from Chapters 4
and 5 that this file goes in the WEB-INF directory of your Web
application. Although a few servers support nonstandard web.xml files
(e.g., Tomcat has one in install_dir/conf that provides defaults for
multiple Web applications), those files are entirely server specific. I am
addressing only the standard version that goes in the Web application's
WEB-INF directory.

To use form-based authentication, supply a value of FORM for the auth-method
subelement and use the form-login-config subelement to give the locations of the
login (form-login-page) and login-failure (form-error-page) pages. In the next
sections I'll explain exactly what these two files should contain. But for
now, note that nothing mandates that they use dynamic content. Thus, these pages
can consist of either JSP or ordinary HTML.

For example, Listing 7.3 shows part of a web.xml file that stipulates
that the container use form-based authentication. Unauthenticated users who
attempt to access protected resources will be redirected to
http://host/webAppPrefix/login.jsp. If they log in successfully, they
will be returned to whatever resource they first attempted to access. If their
login attempt fails, they will be redirected to
http://host/webApp-Prefix/login-error.html.

Creating the Login Page

OK, so the login-config element tells the server to use form-based
authentication and to redirect unauthenticated users to a designated page. Fine.
But what should you put in that page? The answer is surprisingly simple:
all the login page requires is a form with an ACTION of j_security_check, a
textfield named j_username, and a password field named j_password. And, since
using GET defeats the whole point of password fields (protecting the password
from prying eyes looking over the user's shoulder), all forms that
have password fields should use a METHOD of POST. Note that j_security_check is
a "magic" name; you don't preface it with a slash even if your
login page is in a subdirectory of the main Web application directory. Listing
7.4 gives an example.

OK, that was the page for logging in. What about a page for logging
out? The session should time out eventually, but what if users want to
log out immediately without closing the browser? Well, the servlet specification
says that invalidating the HttpSession should log out users and cause them to be
reauthenticated the next time they try to access a protected resource. So, in
principle you should be able to create a logout page by making servlet or JSP
page that looks up the session and calls invalidate on it. In practice, however,
not all servers support this process. Fortunately, changing users is simple: you
just visit the login page a second time. This is in contrast to BASIC
authentication (Section 7.3), where neither logging out nor changing your
username is supported without the user quitting and restarting the browser.

Creating the Page to Report Failed Login Attempts

The main login page must contain a form with a special-purpose ACTION
(j_security_check), a textfield with a special name (j_username), and a password
field with yet another reserved name (j_password). So, what is required to be in
the login-failure page? Nothing! This page is arbitrary; it can contain a link
to an unrestricted section of the Web application, a link to the login page, or
a simple "login failed" message.

Specifying URLs That Should Be Password Protected

The login-config element tells the server which authentication method to use.
Good, but how do you designate the specific URLs to which access should be
restricted? Designating restricted URLs and describing the protection they
should have is the purpose of the security-constraint element. The
security-constraint element should come immediately before login-config in
web.xml and contains four possible subelements: display-name (an optional
element giving a name for IDEs to use), web-resource-collection (a required
element that specifies the URLs that should be protected), auth-constraint (an
optional element that designates the abstract roles that should have access to
the URLs), and user-data-constraint (an optional element that specifies whether
SSL is required). Note that multiple web-resource-collection entries are
permitted within security-constraint.

For a quick example of the use of security-constraint, Listing 7.5 instructs
the server to require passwords for all URLs of the form
http://host/webAppPrefix/ sensitive/blah. Users who supply passwords and belong to the administrator
or executive logical roles should be granted access; all others should be denied
access. The rest of this subsection provides details on the
web-resource-collection, auth-constraint, and display-name elements. The role of
user-data-constraint is explained in the next subsection (Specifying URLs That
Should Be Available Only with SSL).

This rarely used optional subelement of security-constraint gives a name to
the security constraint entry. This name might be used by an IDE or other
graphical tool.

web-resource-collection

This subelement of security-constraint identifies the resources that should
be protected. Each security-constraint element must contain one or more
web-resource-collection entries; all other security-constraint subelements are
optional. The web-resource-collection element consists of a web-resource-name
element that gives an arbitrary identifying name, a url-pattern element that
identifies the URLs that should be protected, an optional http-method element
that designates the HTTP commands to which the protection applies (GET, POST,
etc.; the default is all methods), and an optional description element providing
documentation. For example, the following web-resource-collection entries
(within a security-constraint element) specify that password protection should
be applied to all documents in the proprietary directory (and
subdirectories thereof) and to the delete-account.jsp page in the
admin directory.

It is important to note that the url-pattern applies only to clients that
access the resources directly. In particular, it does not apply to pages
that are accessed through the MVC architecture with a RequestDispatcher (Section
3.8) or by the similar means of jsp:forward or jsp:include (Section 3.5). This
asymmetry is good if used properly. For example, with the MVC architecture a
servlet looks up data, places it in beans, and forwards the request to a JSP
page that extracts the data from the beans and displays it. You want to ensure
that the JSP page is never accessed directly but instead is accessed only
through the servlet that sets up the beans the page will use. The url-pattern
and auth-constraint (see next subsection) elements can provide this guarantee by
declaring that no user is permitted direct access to the JSP page. But,
this asymmetric behavior can catch developers off guard and allow them to
accidentally provide unrestricted access to resources that should be protected.

Core Warning

These protections apply only to direct client access. The security model does
not apply to pages accessed by means of a RequestDispatcher, jsp:forward, or
jsp:include.

auth-constraint

Whereas the web-resource-collection element designates the URLs that should
be protected, the auth-constraint element designates the users that should have
access to protected resources. It should contain one or more role-name elements
identifying the class of users that have access and, optionally, a description
element describing the role. For instance, the following part of the
security-constraint element in web.xml states that only users who are
designated as either Administrators or Big Kahunas (or both) should have access
to the designated resource.

If you want all authenticated users to have access to a resource, use * as
the role-name. Technically, the auth-constraint element is optional. Omitting it
means that no roles have access. Although at first glance it appears
pointless to deny access to all users, remember that these security restrictions
apply only to direct client access. So, for example, suppose you had a JSP
snippet that is intended to be inserted into another file with jsp:include
(Section 3.5). Or, suppose you have a JSP page that is the forwarding
destination of a servlet that is using a RequestDispatcher as part of the MVC
architecture (Section 3.8). In both cases, users should be prohibited from
directly accessing the JSP page. A security-constraint element with no
auth-constraint would enforce this restriction nicely.

Specifying URLs That Should Be Available Only with SSL

Suppose your servlet or JSP page collects credit card numbers. User
authentication keeps out unauthorized users but does nothing to protect the
network traffic. So, for instance, an attacker that runs a packet sniffer on the
end user's local area network could see that user's credit card
number. This scenario is exactly what SSL protects againstit encrypts the
traffic between the browser and the server.

Use of SSL does not change the basic way that form-based authentication
works. Regardless of whether you are using SSL, you use the login-config element
to indicate that you are using form-based authentication and to identify the
login and login-failure pages. With or without SSL, you designate the protected
resources with the url-pattern subelement of web-resource-collection. None of
your servlets or JSP pages need to be modified or moved to different locations
when you enable or disable SSL. That's the beauty of declarative security.

The user-data-constraint subelement of security-constraint can mandate that
certain resources be accessed only with SSL. So, for example, attempts to access
https://host/webAppPrefix/specialURL are handled normally, whereas
attempts to access http://host/webAppPrefix/specialURL are redirected
to the https URL. This behavior does not mean that you cannot supply an
explicit https URL for a hypertext link or the ACTION of a form; it just
means that you aren't required to. You can stick with the simpler
and more easily maintained relative URLs and still be assured that certain URLs
will only be accessed with SSL.

The user-data-constraint element, if used, must contain a transport-guarantee
subelement (with legal values NONE, INTEGRAL, or CONFIDENTIAL) and can
optionally contain a description element. A value of NONE for
transport-guarantee puts no restrictions on the communication protocol used.
Since NONE is the default, there is little point in using user-data-constraint
or transport-guarantee if you specify NONE. A value of INTEGRAL means that the
communication must be of a variety that prevents data from being changed in
transit without detection. A value of CONFIDENTIAL means that the data must be
transmitted in a way that prevents anyone who intercepts it from reading it.
Although in principle (and perhaps in future HTTP versions) there may be a
distinction between INTEGRAL and CONFIDENTIAL, in current practice they both
simply mandate the use of SSL.

For example, the following instructs the server to permit only https
connections to the associated resource:

In addition to simply requiring SSL, the servlet API provides a way to
stipulate that users must authenticate themselves with client certificates. You
supply a value of CLIENT-CERT for the auth-method subelement of login-config
(see "Specifying URLs That Should Be Password Protected" earlier in
this section). However, only servers that have full J2EE support are required to
support this capability.

Now, although the method of prohibiting non-SSL access is standardized,
servers that are compliant with the servlet 2.3 and JSP 1.2 specifications are
not required to support SSL. So, Web applications that use a
transport-guarantee of CONFIDENTIAL (or, equivalently, INTEGRAL) are not
necessarily portable. For example, JRun and ServletExec are usually used as
plugins in Web servers like iPlanet/ Netscape or IIS. In this scenario, the
network traffic between the client and the Web server is encrypted with SSL, but
the local traffic from the Web server to the servlet/ JSP container is not
encrypted. Consequently, a CONFIDENTIAL transport-guarantee will fail. Tomcat,
however, can be set up to use SSL directly. Details on this process are given in
Section 7.5. Some server plugins maintain SSL even on the local connection
between the main Web server and the servlet/JSP engine; for example, the BEA
WebLogic plugin for IIS, Apache, and Netscape Enterprise Server does so.
Furthermore, integrated application servers like the standalone version of
WebLogic have no "separate" servlet and JSP engine, so SSL works
exactly as described here. Nevertheless, it is important to realize that these
features, although useful, are not mandated by the servlet and JSP
specifications.

Core Warning

Web applications that rely on SSL are not necessarily portable.

Turning Off the Invoker Servlet

When you restrict access to certain resources, you do so by specifying the
URL patterns to which the restrictions apply. This pattern, in turn, matches a
pattern that you set with the servlet-mapping web.xml element (see
Section 5.3, "Assigning Names and Custom URLs"). However, most servers
use an "invoker servlet" that provides a default URL for servlets:
http://host/webAppPrefix/servlet/ServletName. You need to make sure
that users don't access protected servlets with this URL, thus bypassing
the access restrictions that were set by the url-pattern subelement of
web-resource-collection. For example, suppose that you use security-constraint,
web-resource-collection, and url-pattern to say that the URL
/admin/DeclareChapter11 should be protected. You also use the
auth-constraint and role-name elements to say that only users in the director
role can access this URL. Next, you use the servlet and servlet-mapping elements
to say that the servlet BankruptcyServlet.class in the disaster package
should correspond to /admin/ DeclareChapter11. Now, the security
restrictions are in force when clients use the URL
http://host/webAppPrefix/admin/DeclareChapter11. No restrictions apply
to http://host/webAppPrefix/servlet/disaster.BankruptcyServlet. Oops.

Section 5.4 (Disabling the Invoker Servlet) discusses server-specific
approaches to turning off the invoker. The most portable approach, however, is
to simply remap the /servlet pattern in your Web application so that all
requests that include the pattern are sent to the same servlet. To remap the
pattern, you first create a simple servlet that prints an error message or
redirects users to the top-level page. Then, you use the servlet and
servlet-mapping elements (Section 5.3) to send requests that include the
/servlet pattern to that servlet. Listing 7.6 gives a brief example.