BUY THIS BOOK
Add to Cart

Print Book $49.99


Safari Books Online

What is this?

Add to UK Cart

Print Book £31.95

What is this?

Looking to Reprint this content?


Java Security
Java Security, Second Edition

By Scott Oaks
Price: $49.99 USD
£31.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Java Application Security
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.
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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-1. The user's machine has access to many things:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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:
stack
Dump the stack every time a permission is checked.
failure
Dump the stack only when a permission is denied.
domain
Dump the protection domain in force when a protection is checked.
jar
When processing a signed jar file, print the signatures in the file, their certificates, and the classes to which they apply.
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: The Default Sandbox
In this chapter, we're going to explore the default sandbox that is used by most Java programs. The default sandbox is designed to allow an end user or system administrator to easily change the parameters of the sandbox so that certain programs may run with a very specific set of permissions. If you're interested in how an applet running in the Java Plug-in can read a file, this chapter provides the information that you need. If you're interested in having your own applications use the (possibly modified) sandbox, this is the place to be.
The information in this chapter is targeted to end users and system administrators: those are the people who are ultimately responsible for defining the security policies that their programs use. Except in special circumstances, it is not possible to change security policies programmatically: in the default sandbox, there is no API that a developer can use that allows her to change a security policy. If you want your program to read a local file, then you must tell the user who will run that program to modify the security policy of his machine before he runs your program. However, developers do need to understand the concepts (and especially the terms) that we define in this chapter.
In the next few chapters, we'll discuss the programmatic details of how the sandbox is implemented; this will give you a better understanding of how Java security works and allow you to develop your own programs that implement a different security policy. But we'll start with the default sandbox, an administratable, flexible model used by most Java programs.
From an administrative point of view, the sandbox is composed of five elements:
Permissions
A permission is a specific action that code is allowed to perform. Permissions may be specific (e.g., the file C:\WINDOWS\Desktop\My Documents\Chapter2.fm can be read but not written or deleted) or very general (e.g., the code can do anything it wants).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Elements of the Java Sandbox
From an administrative point of view, the sandbox is composed of five elements:
Permissions
A permission is a specific action that code is allowed to perform. Permissions may be specific (e.g., the file C:\WINDOWS\Desktop\My Documents\Chapter2.fm can be read but not written or deleted) or very general (e.g., the code can do anything it wants).
Permissions are composed of three elements: the type of the permission, its name, and its actions . The type of the permission is required; it is the name of a particular Java class that implements the permission. Although no programming is involved in administering the default sandbox, administrators must know the Java class name of various permissions in order to allow code to perform those operations.
A few permissions (like java.security.AllPermission , which allows code to do anything) require no name. Otherwise, the name is based on the type of the permission; for example, the name of a file permission is a file or directory name. The names of permissions are often specified as wildcards, such as all files in a directory or all hosts on the local network.
The actions of a permission also vary based on the type of the permission; many permissions have no action at all. The action specifies what may be done to the target; a file permission may specify that a particular file can be read, written, deleted, or some combination of those actions.
Here are three examples of permissions. The first carries only a type; the second carries a type and a name; the third carries a type, a name, and a set of actions:
permission java.security.AllPermission;
permission java.lang.RuntimePermission "stopThread";
permission java.io.FilePermission "/tmp/foo", "read";
Code sources
Code sources are the location from which a class has been loaded along with information about who signed the class, if applicable. The location is specified as a URL, which follows standard Java practice: code can be loaded from the file system through a file-based URL or from the network via a network-based URL.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Permissions
Every Java class carries a set of permissions that defines the activities that the class is allowed to perform. The parameters of the sandbox are wholly defined by these permissions. When a Java program attempts to perform a sensitive operation, the permissions for all active classes are consulted: if every class carries the permission to perform the operation, then the operation is permitted to continue. Otherwise, an exception is thrown in the code, and the operation fails.
Classes that make up the core Java API are always given permission to perform any action. All other classes, including those on the classpath, must explicitly be given permission to perform sensitive operations. For the most part, these permissions are listed in various policy files, along with the code source to which they apply. End users and system administrators define the parameters of the sandbox by administering these policy files.
The permissions within the virtual machine are based on an extensible system of Java classes. Hence, any Java API or application can define its own permissions and ensure that the user has granted those permissions to the API before it can run. For example, the Jini API defines a net.jini.discovery.DiscoveryPermission class. Classes that want to participate in a Jini community must be granted this permission in order to execute the code that participates in Jini's discovery protocol. In general, then, you may need to become familiar with arbitrary permission types in order to use certain APIs.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Keystores
Java code can be signed, which entails obtaining digital certificates and running the jarsigner (or equivalent) tool. You can grant permissions to code that is signed by a particular entity.
If you choose to handle signed code, you must establish a keystore to hold the public keys of the signing entity. Before you run the signed code, you must obtain the public key certificate of the signing entity and install that certificate into your keystore. Some browsers (e.g., Netscape 6) allow you to accept the public key certificate when you first run the signed program, but usually you must install the public key certificate before running the program.
Administration of the keystore is handled by the keytool utility (see Chapter 10). By default, the keystore is held in a file called .keystore in the user's home directory. When you install a public key certificate into the keystore, you give that certificate an alias that is used to look up the certificate in the future. For example, my public key certificate lists my full name and other identifying information, but you may enter it into your keystore with an alias of sdo. This alias is the information that you list in a policy file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Code Sources
Code sources are a combination of codebases and signers. The signer field must match the alias listed in the keystore, as we've just described. Codebases can be any valid URL. Because they are URLs, codebases always use forward slashes, even if the code is being read from the filesystem: file:/C:/files/jdk1.3/ is the correct specification for the directory C:\files\jdk1.3\ (although remember that if the drive is the default drive, you can leave it out and specify the URL as file:///files/jdk1.3/ ).
Codebases can use property substitution much like we showed when discussing file properties. Hence, the codebase for the Java extension directory can be universally specified as file:${java.home}/lib/ext/. This trick applies somewhat to the classpath: if you want a particular set of permissions to apply to all classes on the classpath then you can use the codebase file:${java.class.path}/. However, this works only when there is a single directory or JAR file in the classpath since only those cases result in a correct URL.
The ending of the codebase URL is very important. There are four cases:
  • The URL specifies a jar file (http://www.sun.com/sdo/sdoapp.jar).
    Only the classes in the jar file belong to the codebase.
  • The URL ends with a slash (http://www.sun.com/sdo/).
    Only class files in the given directory belong to the codebase. Jar files in the given directory do not belong to the codebase.
  • The URL ends with an asterisk (http://www.sun.com/sdo/*).
    Both jar files and class files in the given directory belong to the codebase. However, jar and class files in subdirectories of the URL do not belong to the codebase.
  • The URL ends with a hyphen (http://www.sun.com/sdo/-).
    All jar and class files in the given directory and its subdirectories belong to the codebase.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Policy Files
In order to administer the Java sandbox, you list the various permissions we've discussed in a Java policy file. Java virtual machines can use any number of policy files, but there are two that are used by default. There is a global policy file named $JREHOME/lib/security/java.policy that is used by all instances of a virtual machine on a host. We consider this to be a global policy file because it allows an environment where the JRE is mounted from a common server by several machines; each of these machines will share the definitions in this file.
In addition, there is a user-specific policy file called .java.policy that may exist in each user's home directory ($HOME on UNIX systems, C:\WINDOWS on single-user Windows 98 systems, and so on). The set of permissions given to a program is the union of permissions contained in the global and user-specific policy files.
Policy files are simple text files. You can administer them with policytool , or you can edit them by hand. Hand editing is discouraged (in 1.3, policytool writes a warning at the top of the file not to edit it by hand), but real programmers still edit them by hand. Policy files are also used with JAAS, in which case their syntax changes slightly and you must edit them by hand (at least until 1.4, when JAAS becomes integrated with the SDK). So first, we'll see how they look, and then we'll look at how they are created with policytool.
Here's how a typical policy file might look:
keystore "${user.home}${/}.keystore";

// Grant these permissions to code loaded from O'Reilly, regardless of
// whether the code is signed.
grant codeBase "http://www.oreilly.com/" {
  permission java.io.FilePermission "/tmp", "read";
  permission java.lang.RuntimePermission "queuePrintJob";
};

// Grant these permissions to code loaded from Sun but only if it is
// signed by sdo.
grant signedBy "sdo", codeBase "http://www.sun.com/" {
  permission java.security.AllPermission;
};

// Grant these permissions to code signed by jra, no matter where it
// was loaded from
grant signedBy "jra" {
  permission java.net.SocketPermission "*:1024-",
                      "accept, connect, listen, resolve";
};

// Grant these permissions to any code, no matter where it came
// from or whether it is signed
grant {
    permission java.util.PropertyPermission
                     "java.version", "read";
};
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Default Sandbox
And now, putting this all together, let's examine the default sandbox of various Java environments:
Java applications
For applications invoked via the Java command line, the sandbox is initially disabled. To enable the sandbox, you must specify the java.security.manager property like this:
piccolo% java -Djava.security.manager <other args>
                  
Applications may also enable the sandbox programatically by installing a security manager, as we discuss in Chapter 4.
Once enabled, the security manager will use the two default policy files to determine the parameters of the sandbox. You can specify an additional policy file to be used with the java.security.policy property:
piccolo% java -Djava.security.policy=<URL>
                  
You can specify a full URL (e.g., with an http: or file: protocol) or simply list a filename. If you want the given policy file to be the only policy file used (bypassing the ones in $JREHOME/lib/security and the user's home directory), specify two equals signs:
piccolo% java -Djava.security.policy==<URL>
                  
Putting this all together, here's how we would run the class PayrollApp in the default sandbox with additional permissions loaded from the file java.policy in the local directory:
piccolo% java -Djava.security.manager \
                                   -Djava.security.policy=java.policy PayrollApp
                  
Appletviewer
The appletviewer installs a security manager programatically; it cannot be disabled. It will use the standard policy files; to use additional policy files, specify the appropriate policy argument with the -J argument:
piccolo% appletviewer -J-Djava.security.policy=<URL>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The java.security File
Many parameters of the default sandbox are controlled by entries in the java.security file. This file ($JREHOME/lib/security/java.security) can be edited by system administrators, which is particularly effective when it is shared by several end users (though end users, of course, can administer it themselves if required).
That file has several entries that we'll examine throughout this book; an annotated version of it appears in Appendix A. In terms of the default sandbox, here are the important entries:
policy.expandProperties=true
policy.allowSystemProperty=true
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
When we say that there are two default policy files, it's because of the entries in this file (note that the Java property java.home expands to what we've been calling JREHOME). If you would prefer a different set of policy files to be used by default, you can edit the java.security file and change the URLs that are used. You may specify any number of URLs, but they must be numbered consecutively beginning with 1.
As we've seen, users can specify any number of policy files on the command line as well. To prevent users from specifying additional policy files, set the allowSystemProperty property to false. A site that has that value set to false, removes the user's .java.policy entry from this file, and makes the java.security file uneditable by end users has established a sandbox that cannot be modified by end users.
We've shown several examples of how properties can be used in policy files in order to make them more portable. If you want to disable substitution of properties, set the expandProperties property to false.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Comparison with Previous Releases
The default sandbox is essentially unchanged between 1.2 and 1.3. In 1.2, there is no prohibition against defining classes in the java package.
In Java 1.1, the default sandbox is very different. The 1.1 sandbox is determined solely by the security manager installed by the Java program; although it is possible to write a security manager that allows end users and administrators to configure different security policies, few programs followed that course. For most Java applications, this meant that no security manager was ever installed, and the program ran with complete permissions. Java applets run through the appletviewer and early, 1.1-based versions of the Java Plug-in are subject to strict, nonconfigurable restrictions. Using the signing tool of 1.1 (javakey), it is possible to sign Java applets; these applets can then be given permission to perform any operation. However, the 1.1-based signing infrastructure has been deprecated, and an applet signed with javakey will not be given any special permissions in Java 2.
If you need to understand the 1.1 default sandbox, see Chapter 4 for a discussion of the security manager. Appendix D, shows how you can build a 1.1 application to run other Java applications with a security policy that you've written yourself.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
In this chapter, we examined the bounds and adaptability of the Java sandbox. The default sandbox is set up to be administered through a series of policy files, which contain sets of explicit permissions associated with code; this association depends on where the code was loaded from and/or who signed the code.
In the next few chapters, we'll delve into the details of the sandbox and how it is implemented. We'll learn how the sandbox is built up from the low-level components of the Java platform. If you're a developer, we'll learn how to interact with those components while preserving the sandbox model or how you can replace it altogether. And if you're just interested in security, you'll learn the details of how Java achieves its goal of platform security.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Java Language Security
The first components of the Java sandbox that we will examine are those built into the Java language itself. These components primarily protect memory resources on the user's machine, although they have some benefit to the Java API as well. Hence, they are primarily concerned with guaranteeing the integrity of the memory of the machine that is hosting a program: in a nutshell, the security features within the Java language want to ensure that a program will be unable to discern or modify sensitive information that may reside in the memory of a user's machine. In terms of applets, these protections also mean that applets will be unable to determine information about each other; each applet is given, in essence, its own memory space in which to operate.
In this chapter, we'll look at the features of the Java language that provide this type of security. We'll also look at how these features are enforced, including a look at Java's bytecode verifier. With a few exceptions, the information in this chapter is largely informational; because the features we are going to discuss are immutable within the Java language, there are fewer programming considerations than we'll find in later chapters. However, the information presented here is crucial in understanding the entire Java security story; it is very helpful in ensuring that your Java environment is secure and in assessing the security risks that Java deployment might pose. The security of the Java environment is dependent on the security of each of its pieces, and the Java language forms the first fundamental piece of that security.
As we discuss the language features in this chapter, keep in mind that we're only dealing with the Java language itself -- following the common thread of this book, not all security features we're going to discuss apply when the language in question is not Java. If you use Java's native interface to run arbitrary C code, that C code will be able to do pretty much anything it wants to do, even when it violates the precepts outlined in this chapter.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Java Language Security Constructs
In this chapter, we're concerned primarily with how Java operates on things that are in memory on a particular machine. Within a Java program, every entity -- that is, every object reference and every primitive data element -- has an access level associated with it. To review, this access level may be:
private
The entity can only be accessed by code that is contained within the class that defines the entity.
Default (or package)
The entity can be accessed by code that is contained within the class that defines the entity, or by a class that is contained in the same package as the class that defines the entity.
protected
The entity can only be accessed by code that is contained within the class that defines the entity, by classes within the same package as the defining class, or by a subclass of the defining class.
public
The entity can be accessed by code in any class.
The notion of assigning data entities an access level is certainly not exclusive to Java; it's a hallmark of many object-oriented languages. Since the Java language borrows heavily from C++, it's not surprising that it would borrow the basic notion of these access levels from C++ as well (although there are slight differences between the meanings of these access modifiers in Java and in C++).
As a result of this borrowing, the use of these access modifiers is generally thought of in terms of the advantage such modifiers bring to program design: one of the hallmarks of object-oriented design is that it permits data hiding and data encapsulation. This encapsulation ensures that objects may only be operated upon through the interface the object provides to the world, instead of being operated upon by directly manipulating the object's data elements. These and other design-related advantages are indeed important in order to develop large, robust, object-oriented systems. But in Java, these advantages are only part of the story.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Enforcement of the Java Language Rules
The list of rules we outlined above are fine in theory, but they must be enforced somehow. We've always been taught that overwriting the end of an array in C code is a bad thing, but I somehow still manage to do it accidentally all the time. There are also those who willfully attempt to overwrite the ends of arrays in an attempt to breach the security of a system. Without mechanisms to enforce these memory rules, they become simply guidelines and provide no sort of security at all.
This necessary enforcement happens at three different times in the development and deployment of a Java program: at compile time, at link time (that is, when a class is loaded into the virtual machine), and at runtime. Not all rules can be checked at each of these points, but certain checks are necessary at each point in order to ensure the memory security that we're after. As we'll see, enforcement of these rules (which is really the construction of this part of the Java sandbox) varies depending on the origin of the class in question.
The Java compiler is the first thing that is tasked with the job of enforcing Java's language rules. In particular, the compiler is responsible for enforcing all of the rules we outlined above except for the last two: the compiler cannot enforce array bound checking nor can it enforce all cases of illegal object casts.
The compiler does enforce certain cases of illegal object casts -- namely, casts between objects that are known to be unrelated, such as the following code:
Vector v = new Vector(  );
String s = (String) v;
But the validity of a cast between an object of type X to type Y where Y is a subclass of X cannot be known at compile time, so the compiler must let such a construct pass.
Okay, the compiler has produced a Java program for us, and we're about to run the Java bytecode of that program. But if the program came from an unknown source, how do we know that the bytecodes we've received are actually legal?
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Comparisons with Previous Releases
At the level of the Java language, little has changed between Java 1.1 and any release of the Java 2 platform. One thing which has changed is bytecode verification: in 1.1, the virtual machine did not perform bytecode verification of classes on the classpath. This is really a reflection of class loading policies: starting with the Java 2 platform, classes on the classpath are loaded by a traditional class loader, which subjects them to verification.
Bytecode verification seems like a great thing: not only can it help to prevent malicious attacks from violating rules of the Java language, it can also help detect simple programmer errors -- such as when we changed the access modifier of acctNo in our CreditCard class but forgot to recompile our Test class.
Nonetheless, in 1.1 only classes loaded by a browser are subject to bytecode verification. In typical usage, this is a workable policy. Browsers always ensure that the code imported to run an applet is verified, and Java applications are typically not verified. Of course, this may or may not be the perfect solution:
  • If a remote site can talk an end user into installing a local class in the browser's classpath , the local class will not be verified and may violate the rules we've discussed here. In Java 2, this is much harder since the class must be added to the jar file containing the core API classes.
  • You may implicitly rely upon the verifier to help you keep files in sync so that when one is changed, other files are verified against it.
As a user, you (theoretically) have limited control over the verifier -- though such control depends on the browser you are using. If you are running a Java application, you can run java with the -verify option, which will verify all classes. Similarly, if you are using a browser written in Java -- including the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
Because the notion of security in Java is pervasive, its implementation is equally pervasive. In this chapter, we've explored the security mechanisms that are built into the Java language itself. Essentially, at this level the security mechanisms are concerned with establishing a set of rules for the Java language that creates an environment where an object's view of memory is well-known and well-defined so that a developer can ensure that items in memory cannot be accidentally or intentionally read, corrupted, or otherwise misused. We also took a brief look at Java's bytecode verifier, including why it is necessary and why you should turn it on, even for Java applications.
It's important to keep in mind that the purpose of these security constraints is to protect the user's machine from a malicious piece of code and not to protect a piece of code from a malicious user. Java does not (and could not) prevent a user from acting on memory from outside the browser, with possibly harmful results.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: The Security Manager
In the next three chapters, we're going to discuss how the sandbox of a Java application is implemented. The implementation of the sandbox depends on three things:
  • The security manager, which provides the mechanism that the Java API uses to see if security-related operations are allowed.
  • The access controller, which provides the basis of the default implementation of the security manager.
  • The class loader, which encapsulates information about security policies and classes.
We'll start by examining the security manager. From the perspective of the Java API, there is a security manager that actually is in control of the security policy of an application. The purpose of the security manager is to determine whether particular operations should be permitted or denied. In truth, the purpose of the access controller is really the same: it decides whether access to a critical system resource should be permitted or denied. Hence, the access controller can do everything the security manager can do.
The reason there is both an access controller and a security manager is mainly historical: the access controller is only available in Java 2 and subsequent releases. Before the access controller existed, the security manager relied on its internal logic to determine the security policy that should be in effect, and changing the security policy required changing the security manager itself. Starting with Java 2, the security manager defers these decisions to the access controller. Since the security policy enforced by the access controller can be specified by using policy files, this allows a much more flexible mechanism for determining policies. The access controller also gives us a much simpler method of granting fine-grained, specific permissions to specific classes. That process was theoretically possibly with the security manager alone, but it was simply too hard to implement.
But the large body of pre-Java 2 programs dictates that the primary interface to system security -- that is, the security manager -- cannot change; otherwise, existing code that implements or depends on the security manager would become obsolete. Hence, the introduction of the access controller did not replace the security manager -- it supplemented the security manager. This relationship is illustrated in Figure 4-1. Typically, an operation proceeds through the program code into the Java API, through the security manager to the access controller, and finally into the operating system. In certain cases, however, the security manager may bypass the access controller. And native libraries are still outside the domain of either the security manager or the access controller (although the ability to load those libraries may be restricted).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Overview of the Security Manager
When most people think of Java security, they think of the protections afforded to a Java program -- and, more particularly, only by default to a Java applet -- by Java's security manager. There are other important facets of Java's security story, but the role played by the security manager is of paramount importance in defining the security policy under which a particular program will operate.
On one level, the Java security manager is simple to understand, and it's often summarized by saying that it prevents Java applets from accessing your local disk or local network. The real story is more complicated than that, however, with the result that Java's security manager is often misunderstood.
On a simple level, the security manager is responsible for determining most of the parameters of the Java sandbox -- that is, it is ultimately up to the security manager to determine whether many particular operations should be permitted or rejected. If a Java program attempts to open a file, the security manager decides whether or not that operation should be permitted. If a Java program wants to connect to a particular machine on the network, it must first ask permission of the security manager. If a Java program wants to alter the state of certain threads, the security manager will intervene if such an operation is considered dangerous.
The security manager is used only if it is explicitly installed. When you run a Java application, specifying the -Djava.security.manager option installs a security manager. The security manager is installed programatically by the appletviewer and the Java Plug-in.
Hence, this point cannot be overemphasized: Java applications (at least by default) have no security manager while Java applets (again, by default) have a very strict security manager. This leads to a common misconception that exists in the arena of Java security: it's common to think that because Java is said to be secure, it is always secure and that running Java applications that have been installed locally is just as secure as running Java applets inside a Java-enabled browser. Nothing is further from the truth.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Operating on the Security Manager
There are two methods in the System class that are used to work with the security manager itself:
public static SecurityManager getSecurityManager( )
Return a reference to the currently installed security manager object (or null if no security manager is in place). Once obtained, this object can be used to test against various security policies.
public static void setSecurityManager(SecurityManager sm)
Set the system's security manager to the given object. Code that wants to install a security manager must have the runtime permissions createSecurityManager in order to instantiate the security manager object and setSecurityManager in order to install it.
These methods operate with the understanding that there is a single security manager in the virtual machine; the only operations that are possible on the security manager are setting it (that is, creating an instance of the security manager class and telling the virtual machine that the newly created object should be the security manager) and getting it (that is, asking the virtual machine to return the object that is the security manager so that a method might be invoked upon it).
We've already seen how you might use the getSecurityManager( ) method to retrieve the security manager and invoke an operation on it. Setting the security manager is a predictably simple operation:
public static void main(String args[]) {
    System.setSecurityManager(new SecurityManagerImpl(  ));
        ... do the work of the application ...
    }
}
The SecurityManager class provides a complete implementation that uses the access controller to implement the permission-based sandbox we discussed in Chapter 2. When you specify the -Djava.security.manager option to a Java application, the virtual machine executes the setSecurityManager( )
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Methods of the Security Manager
Now that we have an understanding of how the security manager works, we'll look into what protection the security manager actually provides. We'll discuss the public methods of the security manager that perform security checks and when those methods are called, along with the rationale behind each of the methods. Since these methods are all public, they can be called anywhere, including in your own code, although as we've mentioned, that's a rare thing. The real point of this section is so that you can know which methods of the core Java API are affected by the security manager and to give you some background on why these choices were made.
When we discuss the methods below, we speak of them in terms of trusted and untrusted classes. A trusted class is a class of the core Java API or a class that has been granted explicit permission to perform the operation in question.
You'll note that the methods of the security manager correspond fairly well to the set of default permissions that we listed in Chapter 2. In fact, the basic implementation of each method of the security manager is to test to ensure that each active protection domain has permission to perform the desired operation.
The most well-known methods of the security manager class handle access to files on the local network. This includes any files that are on the local disk as well as files that might be physically located on another machine but appear (through the use of NFS, NetWare, Samba, or a similar network-based filesystem) to be part of the local filesystem.
These are the methods the security manager uses to track file access:
public void checkRead(FileDescriptor fd)
public void checkRead(String file)
public void checkRead(String file, Object context)
Check whether the program is allowed to read the given file. The first of these methods succeeds if the current protection domain has been granted the runtime permission with the name
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Comparison with Previous Releases
The security manager has existed in every release of Java. In Java 1.0 and 1.1, the security manager is the only thing that affects the security policy of the program. Because there is no way to install a default security manager via the command line prior to Java 2, most Java 1.0 and 1.1 applications do not have a security manager. In addition, the implementation of the security manager between 1.1-based browsers varies in important aspects between different browser vendors. Even though some browser vendors claim to support the Java 2 platform, they still implement their own security manager rather than using the permission and policy-based default security manager.
We'll discuss many of the major differences here. In addition, in Appendix D, we'll show how a security manager could be implemented in order to specify a policy for applications run in 1.1.
The default notion of what constitutes a trusted class has changed significantly between releases of Java:
  • In Java 1.0, a class that is loaded from the classpath is considered trusted and a class that is loaded from a class loader is considered untrusted.
  • In Java 1.1, the same rule applies but a class that is loaded from a jar file may carry with it a digital signature that allows it to be given extra privileges. These privileges are typically all-or-nothing: if you trust the entity that signed the jar file, then that code can do anything it wants. Some browser vendors have extended that behavior using proprietary APIs.
  • In Java 2, only classes in the core API are considered trusted. Other classes must be given explicit permission to perform the operations we've discussed.
In 1.1, the setSecurityManager( ) method can only be called once, and once installed, the security manager cannot be removed. Attempting to call this method after a security manger has already been installed will result in a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary