ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Java Security, 2nd Edition

Java Application Security

Related Reading

Java Security
By Scott Oaks

by Scott Oaks

This excerpt is Chapter 1 from Java Security, 2nd Edition, published in May 2000 by O'Reilly.

When Java was first released by Sun Microsystems, it attracted the attention of programmers throughout the world. These developers were attracted to Java for different reasons: some were drawn to Java because of its cross-platform capabilities, some because of its ease of programming (especially compared to object-oriented languages like C++), some because of its robustness and memory management, some because of Java's security, and some for still other reasons.

Just as different developers came to Java with different expectations, so too did they bring different expectations as to what was meant by the ubiquitous phrase "Java is secure." Security means different things to different people, and many developers who had certain expectations about the word "security" were surprised to find that their expectations were not necessarily shared by the designers of Java.

This book discusses the features of Java that make it secure. In this book, we'll discuss why Java is said to be secure, what that security means (and doesn't mean), and--most importantly--how to use the security features of the Java platform within your own programs. This last point is actually the focus of this book: while some of Java's security features are automatically a part of all Java programs, many of them are not. In this book, we'll learn about all those features and how to utilize them in our own Java applications.

What Is Security?

Software Used in This Book

The Java Sandbox

Security Debugging

What Is Security?

The first thing we must do is to discuss just what Java's security goals are. The term "security" is vague unless it is discussed in some context; different expectations of the term "security" might lead us to expect that Java programs would be:

Safe from malevolent programs
Programs should not be allowed to harm a user's computing environment, such as Trojan horses and harmful programs that replicate, like computer viruses.
Non-intrusive
Programs should be prevented from discovering private information on the host computer or the host computer's network.
Authenticated
The identity of parties involved in the program -- both the author and the user of the program -- should be verified.
Encrypted
Data that the program sends and receives -- over the network or through a persistent store such as a filesystem or database -- should be encrypted.
Audited
Potentially sensitive operations should always be logged.
Well-defined
A well-defined security specification should be followed.
Verified
Rules of operation should be set and verified.
Well-behaved
Programs should be prevented from consuming too many system resources: too much CPU time, too much memory, and so on.
C2 or B1 certified
Programs should have certification from the U.S. government that certain security procedures are followed.

In fact, while all of these features could be part of a secure system, only the first two were within the province of Java's 1.0 default security model. Other items in the list have been introduced in later versions of Java: authentication was added in 1.1, encryption is available as an extension to the Java 2 platform, and auditing can be added to any Java program by providing an auditing security manager. Still others of these items will be added in the future. But the basic premise remains that Java security was originally and fundamentally designed to protect the information on a computer from being accessed or modified (including a modification that would introduce a virus) while still allowing the Java program to run on that computer.

The point driving this notion of security is the new distribution model for Java programs. One of the driving forces behind Java, of course, is its ability to download programs over a network and run those programs on another machine. This is something most computer users do today within the context of a Java-enabled browser, although the idea behind portable code like this is beginning to seep into other applications, such as those based on Jini technology. Coupled with the widespread growth of Internet use--and the public-access nature of the Internet--Java's ability to bring programs to a user on an as-needed, just-in-time basis has been a strong reason for its rapid deployment and acceptance.

The nature of the Internet created a new and largely unprecedented requirement for programs to be free of viruses and Trojan horses. Computer users had always been used to purchasing shrink-wrapped software. Many soon began downloading software via FTP or other means and then running that software on their machines. But widespread downloading also led to a pervasive problem of malevolent attributes both in free and (ironically) in commercial software, a problem which continues unabated. The introduction of Java into this equation had the potential to multiply this problem by orders of magnitude, as computer users now download programs automatically and frequently.

For Java to succeed, it needed to circumvent the virus/Trojan horse problems that plagued other models of software distribution. Hence, the early work on Java focused on just that issue: Java programs are considered safe because they cannot install, run, or propagate viruses and because the program itself cannot perform any action that is harmful to the user's computing environment. And in this context, safety means security. This is not to say that the other issues in the above list are not important--each has its place and its importance (in fact, we'll spend a great deal of time in this book on the third and fourth topics in that list). But the issues of protecting information and preventing viruses were considered most important; hence, features to provide that level of security were the first to be adopted. Like all parts of Java, its security model is evolving (and has evolved through its various releases); many of the notions about security in our list will eventually make their way into Java.

One of the primary goals of this book, then, is to explain Java's security model and its evolution with each subsequent release. In the final analysis, whether or not Java is secure is a subjective judgment that individual users will have to make based on their own requirements. If all you want from Java is freedom from viruses, any release of Java should meet your needs. If you need to introduce authentication or encryption into your program, you'll need to use a 1.1 or later release of Java. If you have a requirement that all operations be audited, you'll need to build that auditing into your applications. If you really need conformance with a U.S. government-approved definition of security, Java is not the platform for you. We take a very pragmatic view of security in this book: the issue is not whether a system that lacks a particular feature qualifies as "secure" according to someone's definition of security. The issue is whether Java possesses the features that meet your needs.

Software Used in This Book

The information in this book is based on the Java 2 Standard Edition, version 1.3 (or 1.3, for short). There are slight differences between how Java security operates in 1.2 (that is, the Java 2 Standard Edition, version 1.2) and 1.3. When we refer to a specific release, we'll use its number; otherwise, we'll say Java 2 to refer to either platform.

In addition, there are great differences in how Java security operates between the Java 1.1 and the Java 2 platform. While we concentrate on Java 1.3, the end of each chapter contains a section that elucidates the differences between Java 1.3 and previous releases of Java. Some of the very different topics of Java 1.1 are presented in the appendices of this book; it is not generally recommended that you use the facilities and APIs discussed there since they are not compatible with the Java 2 platform.

We present information in this book from three standard Java extensions: the Java Cryptography Extension (JCE) version 1.2.1, the Java Secure Sockets Extension (JSSE) version 1.0.2, and the Java Authentication and Authorization Service (JAAS) version 1.0. Each of these contributes certain technologies to the Java security story. These extensions require 1.3.

Information about the extensions is presented thoughout the book as it makes sense. The JSSE API defines a set of classes that are used to perform SSL operations, and these are discussed in a separate chapter. The JSSE API also defines a set of classes that are used for key management; these are discussed along with the classes in the core API that handle key management. So even though these three packages are standard extensions, we recommend that you install them now along with the SDK so that you can become familiar with their features when they arise. In version 1.4, all these extensions are scheduled to be included in the core SDK, which is another reason why it helps to think of them as an integrated unit.

In the next few pages, we'll discuss how to obtain and install the platform and extensions. Configuring the extensions may require some steps that you don't understand right now because they have various security options that apply to them. However, we recommend that you just follow the instructions for now and install the extensions. The extensions use Java's standard security framework, and as we discuss each aspect of the framework, we detail how the extensions relate to that aspect. Thus, while the core features of each extension is discussed in its own chapter, information about the extensions appears throughout the book.

The Java 2 Platform

The core Java 2 platform supplies the basic facilities of Java security:

Java 2 version 1.3 can be obtained for Solaris, Linux, and Windows systems from http://java.sun.com/j2se/1.3/. If you need Java for other platforms, check with your platform vendor or check http://java.sun.com/cgi-bin/java-ports.cgi.

The Java 2 platform contains two flavors: the Software Development Kit (SDK, also known historically as the JDK) and the Java Runtime Environment (JRE). Administration of the security model applies to both the JRE and SDK, but to use the security APIs that we discuss, you'll need the SDK (which includes the JRE). Throughout this book, we'll use the environment variable $JDKHOME to refer to the directory in which the Java 2 SDK was installed and the $JREHOME variable to refer to the directory in which the Java 2 JRE was installed. If you installed the SDK into C:\files\jdk1.3 then $JDKHOME would be C:\files\jdk1.3 and $JREHOME would be C:\files\jdk1.3\jre.

Installed or Bundled Extensions?

When you work with the extensions that we use in this book, you have the option of treating them as installed or bundled extensions.

Installed extensions are much easier to work with: they require no special configuration once they are installed. However, they must be installed into special directories within $JREHOME, and they may require files in $JREHOME to be modified. Depending on your setup, this may require special operating system privileges.

A bundled extension requires no special installation privileges, but it does require you to set up things within your environment: you must modify your classpath, and you must set up special policy files. In addition, some of this configuration must be done programatically, so this option will not work for third-party applications. We assume in our examples that you've set up the extensions as installed extensions.

The Java Cryptography Extension

JCE leverages the Java 2 core platform's security architecture to provide a variety of cryptographic operations:

JCE can be downloaded from http://java.sun.com/products/jce/. Version 1.2.1 is an important version because it takes advantage of a change in the policy of the United States regarding export controls of cryptographic engines. Prior to early 2000, the United States government considered cryptographic engines to be a munition and severely restricted the export of such technology. After this policy was changed in early 2000, JCE 1.2.1 was modified to meet the new standards. As a result, although it performs strong encryption, JCE 1.2.1 can be exported from the United States.

JCE consists of some documentation and a lib directory that contains four jar files: US_export_policy.jar, jce1_2_1.jar, local_policy.jar, and sunjce_provider.jar. Like most extensions, you can install JCE as a bundled or unbundled extension.

To use JCE as an installed extension, you must:

To use JCE as an unbundled extension, you must:

More details about how this works can be found in later chapters. Chapter 8, Security Providers, discusses the addition to the java.security file and its programmatic alternative, and the .java.policy file is discussed in Chapter 2, The Default Sandbox.

The Java Secure Sockets Extension

JSSE provides Secure Sockets Layer (SSL) encryption facilities. If you need to communicate with an SSL server or SSL client, you can use the APIs in this extension. If you are writing both a client and server and want to do encryption, you can use this extension or you can use the cipher facilities of JCE.

JSSE can be downloaded from http://java.sun.com/products/jsse/. Version 1.0.2 takes advantage of the relaxed export restrictions of the U.S. and is exportable. Unlike JCE, however, there are still two different versions of JSSE: one for domestic use (use within the United States and Canada) and one for global use. The difference between these two versions is that the domestic version allows you to substitute new implementations of the SSL algorithms. Such substitution is still prohibited by export rules, so the global version does not allow it. However, both versions provide exactly the same API and the same key strength for their encryption.

JSSE consists of documentation and a lib directory containing three jar files: jcert.jar, jnet.jar, and jsse.jar. To use JSSE as an installed extension, you must:

To use JSSE as an unbundled extension, you must:

The Java Authentication and Authorization Service

JAAS provides for user authentication within the Java platform. It performs a unique function in the Java platform. All of the core facilities of Java's security design are intended to protect end users from the influences of developers: end users give permissions to developers to access resources on the end user's machine. JAAS, on the other hand, allows developers to grant (or deny) access to their programs based on the authentication credentials provided by the user.

JAAS can be downloaded from http://java.sun.com/products/jaas/. It comes in two parts: a Java library which defines the interface to the service (the JAAS proper), and platform-specific modules to perform the authorization (the JAAS modules). Sample modules are available to perform authentication based on JNDI directory services, Windows NT login services, and Solaris login services.

JAAS itself contains documentation and a lib directory with a single jar file (jaas.jar). The jar file should either be installed into $JREHOME/lib/ext, or the user must add it to her classpath.

The lib directory of the JAAS modules contains an additional jar file (jaasmod.jar) that must be handled similarly. It also contains platform-specific shared libraries. On Solaris systems, these libraries must be installed into $JREHOME/lib/sparc. If that is not possible, the libraries can be placed into any directory (e.g., /files/jaasmod1_0/lib) and that directory can be added to the user's LD_LIBRARY_PATH.

On Microsoft Windows systems, these libraries are named nt.dll, nt.lib, and nt.exp and they must be installed into $JREHOME\bin. If that is not possible, then you must set the java.library.path property on the command line. For instance, if the libraries are in \files\jaasmod1_0\lib, you would specify the following property on the command line:

-Djava.library.path=\files\jaasmod1_0\lib

No modification to the java.security file is required for JAAS.

More About Export Controls

Encryption and Weaponry

The whole question of importing and exporting encryption technology occurs because it is often classified as a munition. While this position is sometimes questioned, it comes from a long tradition in computer science.

During WWII, the Allies waged a successful and pivotal campaign in the Atlantic against the Axis navy. The success of this campaign was greatly due to the work of Alan Turing, who with his colleagues broke the German encryption algorithm known as Enigma. Turing was also one of the founding fathers of modern computer science, much of which was based on the work he developed in service to his country during the war.

Ironically, the reward that Turing reaped for his efforts was that some years after the war, he was arrested and forced to undergo harmful chemical treatments because he was gay. There's an odd parallel here: many of the harsh restrictions that are sometimes placed on encryption technology make no more sense in a world with a global Internet than did England's persecution of Alan Turing in the 1950s. Perhaps the relaxation of export restrictions is a good sign in general.

The U.S. is not the only government that regulates the use of encryption, and encryption software can face import restrictions as well as export restrictions. In France, for example, it is illegal to import many encryption packages without a license. Other countries have regulations for cryptography, but in most cases they are less onerous than those of the United States. However, it is always wise to check your local policies to be sure (see Appendix B, Security Resources, for resources to find more information about these limitations).

Even though the U.S. has relaxed its export rules, some restrictions still apply. You may not export either JCE or JSSE (and, hence, any programs that use them) to the following countries: Afghanistan, Cuba, Iran, Iraq, Libya, North Korea, Serbia/Montenegro (Yugoslavia), Sudan, Syria and parties listed on the Denied and Restricted Parties List (available at http://bxa.fedworld.gov/prohib.html). Additionally, it is Sun company policy not to ship products to Burma.

The encryption extensions, like many aspects of the Java platform, allow for third-party implementations; just like you can buy a third-party JDBC driver, you can buy third-party implementations of JCE. However, many of the popular algorithms that are used by the extensions are patented algorithms, which also restricts their use. RSA Data Security, Inc. holds a patent in the U.S. on several algorithms involving RSA encryption and digital signatures; Ascom System AG in Switzerland holds both U.S. and European patents on the IDEA method of performing encryption. If you live in a country where these patents apply, you can't use these underlying algorithms without paying a licensing fee to the patent holder. In particular, this means that many of the third-party security providers and third-party implementations of JCE cannot be used within the United States because of patents held by RSA (although some of them have reached a licensing agreement with RSA Data Security, Inc.--again, it is best to check with the provider to see what restrictions might apply). Sun has an agreement with RSA Data Security to redistribute its implementation of the RSA algorithms.

Note that import and export restrictions apply only to the encryption technology contained within JCE and JSSE. Although the core Java APIs perform important cryptographic operations, those operations are not considered to be munition-grade operations.

Other Software Versions

Though Java-enabled browsers are very popular, we do not discuss most of the popular ones. This is because their security implementations are very different from the official Java security model. Both Netscape and Microsoft, for example, introduced new (and proprietary) APIs to allow for security extensions. Both companies also developed their own (again proprietary) mechanism to sign applets.

The better way to run Java applets from within a browser is to use the Java Plug-in, which comes standard with every release of the Java 2 platform; when you install Java 2, you install the Java Plug-in. In Netscape 6 and later releases, the Java Plug-in is the only way to run Java applets; there is no Java virtual machine built into Netscape 6. The Plug-in is also compatible with Internet Explorer 4.x and higher, as well as Netscape 4.x versions.

The security model of the Java Plug-in is exactly the same as that of the Java platform that we describe within this book. Where the security model of older browsers is different, we point that out, and we provide directions to the vendor's web sites that give information on their non-standard systems.

The Java Sandbox

When Java security is discussed, the discussion typically centers around Java's applet-based security model -- the security model that is embodied by Java-enabled browsers. It's considered "applet-based" because in early versions of Java, it applied only to applets that run within a Java-enabled browser. In the Java 2 platform, however, this security model can apply to any Java application as well as to the Java Plug-in, which allows newer browsers to run Java 2 applets. The Java 2 security model is also configurable by an end user or system administrator so that it can be made less restrictive than earlier implementations of that model.

This security model centers around the idea of a sandbox. The idea is when you allow a program to be hosted on your computer, you want to provide an environment where the program can play (i.e., run), but you want to confine the program's play area in certain bounds. You may decide to give the program certain toys to play with (i.e., you may decide to let it have access to certain system resources), but in general, make sure that the program is confined to its sandbox.

This analogy works better when you consider it from the view of a close relative rather than from the view of a parent. If you're a parent, you probably consider the purpose of a sandbox to be to provide a safe environment for your child to play in. When my niece Rachel visits me, however, I consider the purpose of a sandbox not (only) to be to protect her, but also to protect my grandmother's china from her. I love my niece, but I can't give her leave to run through my house; I enjoy running the latest cool applet on the Internet, but I can't give it leave to run through my filesystem.

The Java sandbox is responsible for protecting a number of resources, and it does so at a number of levels. Consider the resources of a typical machine as shown in Figure 1. The user's machine has access to many things:

Diagram: a machine has access to many resources.
Figure 1. A machine has access to many resources

Each of these resources needs to be protected, and those protections form the basis of Java's security model. We can imagine a number of different-sized sandboxes in which a Java program might run:

The sandbox, then, is not a one-size-fits-all model. Expanding the boundaries of the sandbox is always based on the notion of trust: when my one-year-old niece comes to visit, there's very little in the sandbox for her to play with, but when my six-year-old godchild comes to visit, I trust that I might give her more things to play with. In the hands of some visitors, a toy with small removable parts would be dangerous, but when I trust the recipient, it's perfectly reasonable to include that item in the sandbox. And so it is with Java programs: in some cases, I might trust them to access my filesystem; in other cases, I might trust them to access only part of my filesystem; and in still other cases, I might not trust them to access my filesystem at all.

Applets, Applications, and Programs

In early versions of Java, only applets were run within a sandbox. In the Java 2 platform, all programs have the potential to run in a sandbox. Applets that run through the Java Plug-in or the appletviewer will always run in a sandbox, and applications that are run via the command line (or by clicking an icon on the desktop) may optionally be set up to use a sandbox. Applications also have the option of programatically installing new versions of the sandbox.

Hence, in the Java 2 platform there is little distinction between the security level of an applet and an application. There are programmatic differences, of course, but both are subject to the same security model, and the security model for both is administered and programmed in the same way. There is one significant difference, however: applets always run with Java's security model (even if that model has been administered such that the applet is allowed to do anything it wants to), and an application will only run under the security model if it is told to do so. This is typically done by the end user by specifying a command-line parameter; it may be done by the program developer who specifies that parameter in a script that starts the application, and it may be done by the developer who inserts code into his program.

Any program, including an applet, can change the behavior of the sandbox under certain circumstances. However, most of them will use Java's default sandbox. The default sandbox, as we'll see in Chapter 2, The Default Sandbox, is very flexible; it allows the user who runs the program to determine exactly how the sandbox will operate. This moves the definition of the security policy to the end user or system administrator of the machine running the program.

Anatomy of a Java Program

The anatomy of a typical Java program is shown in Figure 2. Each of the features of the Java platform that appears in a rectangle plays a role in the development of the Java security model. In particular, the elements of the Java security policy are defined by:

The bytecode verifier
The bytecode verifier ensures that Java class files follow the rules of the Java language. In terms of resources, the bytecode verifier helps enforce memory protections for all Java programs. As the figure implies, not all classes are subject to bytecode verification.
The class loader
One or more class loaders load all Java classes. Programatically, the class loader can set permissions for each class it loads.
The access controller
The access controller allows (or prevents) most access from the core API to the operating system, based upon policies set by the end user or system administrator.
The security manager
The security manager is the primary interface between the core API and the operating system; it has the ultimate responsibility for allowing or preventing access to all system resources. However, it exists mostly for historical reasons; it defers its actions to the access controller.
The security package
The security package (that is, classes in the java.security package as well as those in the security extensions) allows you to add security features to your own application as well as providing the basis by which Java classes may be signed. Although it is only a small box in this diagram, the security package is a complex API and discussion of it is broken into several chapters of this book. This includes discussions of:
The key database
The key database is a set of keys used by the security infrastructure to create or verify digital signatures. In the Java architecture, it is part of the security package, though it may be manifested as an external file or database.

Diagram of a Java application.
Figure 2. Anatomy of a Java application

The last two items in this list have broad applicability beyond expanding the Java sandbox. With respect to the sandbox, digital signatures play an important role because they provide authentication of who actually provided the Java class. As we'll see, this provides the ability for end users and system administrators to grant very specific privileges to individual classes or signers. But a digital signature might be used for other applications. Let's say that you're deploying a payroll application throughout a large corporation. When an employee sends a request to view his payroll information, you really want to make sure that the request came from that employee rather than from someone else in the corporation. Often, this type of application is secured by a simple password, but a more secure system could require a digitally signed request before it sent out the payroll information.

This list is also a rough outline of the path we'll take through this book. We'll start by looking at the default sandbox and how it can be administered. Following that, we'll look at the details of everything that makes up that sandbox, from the bytecode verifier through the access controller. Then we'll move into the security APIs that allow you to add digital signatures and encryption to your own applications.

Security Debugging

The Java security packages include debugging code that you can enable via a system property. The property in question is java.security.debug, and it may be set to the following values:

all
Turn on all the debugging options.
access
Trace all calls to the checkPermission( ) method of the access controller. This allows you to see which permissions your code is requesting, which calls are succeeding, and which ones are failing. This option has the following sub-options. If no sub-option is specified, then all are in force:
policy
Print information about policy files as they are parsed, including their location in the filesystem, the permissions they grant, and the certificates they use for signed code.
scl
Print information about the permissions granted directly by a secure class loader (rather than granted through a policy file).

These options should be given as a comma-separated list (including the sub-options for the access option). For example, to see the permissions granted by the secure class loader and see a stack trace when a permission check fails, you would specify -Djava.security.debug=scl,access,failure on the command line.

JSSE extends this facility by consulting the javax.net.debug property for the following options:

all
Turn on all options and sub-options.
ssl
Turn on SSL debugging. This option has the following sub-options (all of which are in force if none are specified):
record
Print a trace of each SSL record (at the SSL protocol level).
handshake
Print each handshake message as it is received.
keygen
Print key generation data for the secret key exchange.
session
Print SSL session activity.
defaultctx
Print the default SSL initialization information.
sslctx
Print information about the SSL context.
sessioncache
Print information about the SSL session cache.
keymanager
Print information about calls to the key manager.
trustmanager
Print information about calls to the trust manager.
data
For handshake tracing, print out a hex dump of each message.
verbose
For handshake tracing, print out verbose information.
plaintext
For record tracing, print out a hex dump of the record.

As you progress through the samples in the book, you can turn various options on in order to see more information about what's going on.

Summary

Security is a multifaceted feature of the Java platform. There are a number of facilities within Java that allow you to write a Java application that implements a particular security policy, and this book will focus on each of those facilities in turn. These features are important within a Java-enabled browser, and they are also important with Java applications, particularly as applications become more distributed.

In addition, the security package allows us to create applications that use generic security features--such as digital signatures--for many purposes aside from expanding the Java sandbox. This other use of the security package will also be a constant theme throughout this book.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.