In this chapter you'll learn about the security of Java applets and programs. You'll learn about the threats faced by those who use Java applets and programs and the security restrictions placed on Java applets. You'll cover the security features of the Java language, compiler, and runtime environment. You'll also explore the security mechanisms implemented by Java-enabled browsers. When you finish this chapter, you'll be aware of the security issues associated with Java applets and programs and of the ways Java and Java-enabled browsers resolve these issues.
Those who use Java applets and programs face significant security threats. Information on their computers may be selectively altered, destroyed, or disclosed by those who develop Java applets and programs and those who have the ability to modify them. Damage may result from deliberately planned attacks on your system or from errors that are introduced into Java source or compiled code. Although the threat associated with inadvertent errors is far less than with malicious actions, it cannot be discounted. The damage resulting from instances of Murphy's Law often exceeds that of the most cunning hackers. However, this chapter examines all security threats as if they are the result of deliberate hostile actions.
The threat posed by a standalone Java program is the same as any other program that you run on your computer. When a program runs on your behalf, it has access to your files, system capabilities, and system resources, and can use this access to modify, delete, or compromise sensitive data or misuse these capabilities and resources. The program's access is limited only by the access controls enforced by your operating system or other security software. In most cases, these access controls are nonexistent or minimally effective. The danger of running a standalone Java program is the same as running any other program that you do not develop yourself. Unless you can verify the security of the program through rigorous analysis and testing, you are forced to trust the programs not to cause deliberate or inadvertent damage.
The level of trust that you place in a program is usually based on the source from which you obtained the program. You generally place more trust in programs that you receive from well-established software vendors than those that you download from obscure, publicly accessible file archives. Standalone Java programs provide no more or less security than any other programs you may encounter. They may be written to cause the same level of damage to your system as a program that is written in another programming language. Because of this unfortunate fact, the security of standalone Java programs is not explicitly considered in the remainder of this chapter.
The threat posed by Java applets expands the threat posed by standalone programs to the Web as a whole. Since Web pages may contain applets, scripts, and other types of embedded programming, clicking on a Web page is equivalent to executing a program. The increased danger associated with applets is the lack of control that you have over the programs you execute. Any Web page may bring an insidious intruder into your system. You may, of course, disable the execution of applets by your browser, but doing so eliminates all the potential benefits of Java.
To counter the threat posed by those who would bring harm to your
computer and to mitigate the risk associated with running applets,
the developers of Java and Java-enabled browsers have included
a powerful set of security features in the Java language, compiler,
runtime system, and Web browsers. These security features include
security mechanisms that have been specifically designed to eliminate
potential security vulnerabilities; other mechanisms, although
not intentionally designed for security purposes, encumber both
deliberate and inadvertent security threats. The following sections
describe these security features.
This section and its subsections address the security issues associated with running applets that are loaded over a network. The same issues apply to applets that are loaded from a local file system, but the potential risks are somewhat lower. The intent is to deal with the worst-case scenario.
A number of features have been incorporated into the Java language to make it more reliable and capable. Although these features may not have been driven by security concerns, they still help to minimize security risks. The most important of these features is the removal of all pointer-based operations from the Java language. The absence of pointers eliminates entire classes of security vulnerabilities related to memory browsing, the modification of memory-resident code, and illegal access to security-related objects.
Java's use of strong typing also contributes to security. All objects are associated with a well-defined type and cannot be freely converted from one type to another. Methods cannot be used with classes to which they do not apply. Methods cannot return objects of a type that is incompatible with their return type. Strong typing enforces the Java object-oriented approach and prevents numerous kinds of errors that could lead to security-related malfunctions.
The Java compiler also provides features that support security. These features are implemented in the form of compiler checks that prevent errors and undesired actions.
The compiler enforces Java's strong typing by generating compilation errors for statements that violate the language's strong typing rules. It ensures that all methods are appropriate for the objects for which they are invoked.
The compiler checks array operations to make sure that they are valid for the array objects being acted on and that memory overrun errors do not occur. These checks are duplicated and extended by the runtime system.
The compiler checks all class, interface, variable, and method accesses to ensure that the accesses are consistent with the access modifiers used in their declaration. This prevents classes, interfaces, variables, and methods from being used in unintended ways and enforces the information hiding capabilities provided by the access modifiers.
The compiler generates code that treats String objects as constants and supports String operations through the StringBuffer class. This eliminates overrun errors that could cause in-memory modification of data or code.
The compiler also prevents uninitialized variables from being read and constants from being modified. These checks eliminate errors resulting from incorrect variable reading and writing.
The Java runtime system is designed to prevent applets from modifying, deleting, or disclosing your files, accessing in-memory programs and data, and misusing network resources. This is accomplished by preventing applets from accessing files on your computer, not providing or disallowing services that enable control over other programs, data, or the host operating system, and restricting network connections to the host computer from which an applet is loaded. The specific security mechanisms that implement these controls are discussed in the following subsections.
Applets are loaded over a network using a class loader. The class loader prevents classes that are loaded from the network from masquerading as or conflicting with classes that are resident on the local file system. This ensures that the security-critical classes of the Java API are not replaced by less trustworthy classes that are loaded over a network.
The class loader separates local and network-loaded classes by placing those classes from a particular network host into a name space that is unique to that host. This approach also keeps network-loaded classes from different hosts from conflicting with each other.
The security of classes that are loaded over a network is verified using the bytecode verifier. The bytecode verifier checks that the loaded classes are correctly formed and that they do not have the capability to violate type and name space restrictions.
The verifier uses a mini theorem prover to prove that the .class file initially satisfies certain security constraints and that when it is executed it will always transition into states in which these security constraints are satisfied. This proof by induction verifies that basic security rules will be enforced throughout the execution of the .class file. The verifier proves that no illegal conversion between types can occur, that parameters are correct for the methods and instructions to which they apply, that stack operations do not cause overflows or underflows, that access modifiers are enforced, that no forged pointers can be created, and that register operations do not lead to errors.
The memory locations of Java classes and objects are determined at runtime based on the platform hosting the runtime system and the current memory allocation maintained by the operating system. By performing memory layout decisions at runtime, the potential for inducing errors that cause memory overruns and lead to security malfunctions is greatly reduced. This is because it is very difficult to predict the memory locations at which objects will be stored during code execution. Without this knowledge, complex memory overrun attacks are thwarted.
The Java garbage collector reduces the likelihood that an applet or program may make mistakes in its management of memory resources. Since memory deallocation is automatically handled through the garbage collection process, errors resulting from multiple deallocation of the same memory area or failure to deallocate memory are avoided.
Runtime array bounds checking also reduces the likelihood that errors resulting in illegal memory accesses can occur. By confining array operations to valid array locations, these potential security-related errors are prevented.
The Java security manager provides a central decision point for implementing Java security rules. This ensures that security access controls are implemented in a manageable and consistent manner. The SecurityManager class of the java.lang package may be overridden to implement a custom security policy for standalone Java programs such as those that load applets. A SecurityManager object cannot, however, be created, invoked, or accessed by a network-loaded applet. This prevents applets from modifying the security policy implemented by the runtime system's SecurityManager object.
The applet security policy implemented by the default SecurityManager object varies from one browser to another. Netscape Navigator 2.0 implements a security policy that enforces the following rules for applets that are loaded over a network:
Keeping Java secure is an ongoing process. Several security flaws have been identified to date and it is reasonable to expect that new Java security flaws will continue to be found. Sun and Netscape have responded quickly to newly discovered security flaws, often releasing fixes within days. As new versions of Java are released and the Java API is expanded, new security flaws will most likely be introduced. To stay current with Java security issues, you should periodically review the FAQ on applet security maintained by JavaSoft. This FAQ contains the status of all known security-related bugs in Java and Java-enabled browsers. The FAQ is located at the URL http://java.sun.com/sfaq/. A source of information on general Java bugs in the JDK 1.0 release can be found at http://www.javasoft.com/JDK-1.0/knownbugs.html.
In this chapter you have learned about the security of Java applets and programs. You have learned about the threats faced by those who use Java applets and programs and the security restrictions placed on Java applets. You have covered the security features of the Java language, compiler, and runtime environment and explored the security mechanisms implemented by Java-enabled browsers. The next and final chapter examines Java platforms and extensions.