Register for EarthWeb's Million Dollar Sweepstakes!
home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Platinum Edition Using HTML 4, XML, and Java 1.2
(Publisher: Macmillan Computer Publishing)
Author(s): Eric Ladd
ISBN: 078971759x
Publication Date: 11/01/98

Bookmark It

Search this book:
 
Previous Table of Contents Next


These three mechanisms work together to ensure that

  Only the proper classes are loaded.
  Each class is in the proper format.
  Untrusted classes are not allowed to execute dangerous instructions.
  Untrusted classes are not allowed to access system resources.

Understanding the Class Loader When a Java-aware browser sees the <APPLET> tag, it invokes the class loader and asks the class loader to load the specified applet. The class loader defines a namespace associated with that particular Web page. Classes loaded as part of this applet are not allowed to access other classes (although they can access classes that form part of the standard Java libraries). Figure 41.2 illustrates the class loader’s namespaces.


FIGURE 41.2  The Java class loader uses namespaces to isolate one applet from another.

The security provided by a class loader is only as good as the class loader itself. If the class loader was built by Sun or based on Sun’s template, it should provide the safeguards described here. Sun’s model class loader contains checks to make sure the applet does not install its own class loader, for example, or call methods that are used solely by the class loader. If the browser vendor has not followed Sun’s guidelines, the class loader may have security holes.


NOTE:  Any application designer can write his or her own class loader. End users should not trust a class loader unless they trust the application developer.

Security Afforded by the Bytecode Verifier After a class is loaded (by the class loader) it is inspected by the bytecode verifier. The bytecode verifier includes a sophisticated theorem prover that ensures that the applet does not forge pointers, circumvent access restrictions, or convert objects illegally. Just as the class loader’s namespace mechanism ensures that one applet cannot interfere with another, the bytecode verifier ensures that an applet cannot wreak havoc within its own namespace. The bytecode verifier also checks for stack overflow or underflow—a traditional way malicious programmers have breached system security. We’ll talk more about the bytecode verifier later in this chapter, in the section “The Security of Compiled Code.”

Working with the JVM’s Security Manager The final set of checks at the JVM level is made by the JVM’s Security Manager. The Security Manager watches out for “dangerous” operations—those that could be exploited by a malicious programmer. The Security Manager must agree any time the applet attempts to access any of the following:

  Network communications
  Protected information (including the hard drive or personal data)
  Operating-system level programs and processes
  The class loader
  Libraries of Java classes (known as packages)

The Security Manager is also responsible for preserving thread integrity. That is, code in one group of threads cannot interfere with code in another group of threads, even if the two groups have the same parent applet.

  To learn more about threads, see “Adding Animation” on p. 1104.

Language-Level Safeguards

Many languages, such as SmallTalk, enable the programmer to easily convert objects of one sort to objects of another. This loose typing enables programmers to get code up and running quickly, but also opens opportunities for the malicious programmer (in addition to leaving opportunities for software defects).

Strongly typed languages such as Ada are somewhat more difficult to use, but they generally result in programs with fewer defects and tighter compiled code. For this reason loosely typed languages are popular for prototyping, and strongly typed languages are often used for production code.

C and C++ offer a combination of typing methods. The language presents itself as being strongly typed—the compiler needs to be able to determine the type of each object—but the programmer can override a type and coerce an object of one type into a different type. This override mechanism is called casting. To cast an object of type Book to be of type Volume, you could write

Volume myVolume = (Volume) aBook;

Java’s approach to typing provides three security benefits:

  Objects cannot be cast to a subclass without an explicit runtime check.
  All references to methods and variables are checked to make sure that the objects are of the correct type.
  Integers cannot be converted into objects, and objects cannot be converted to integers.

In general, much of C and C++’s strength comes from the capabilities of those languages to use pointers—variables that hold memory addresses of other data. Although you’ll sometimes see descriptions of Java that claim the language has no pointers, the fact is that everything in Java is a pointer—they’re just not accessible by the user. The reason pointers are “invisible” is that the Java designers removed the capability to point a pointer to an arbitrary location. This capability, often used by C and C++ programmers, is called pointer arithmetic—the capability to modify a pointer so that it points to a new location. Pointer arithmetic enables a malicious C or C++ programmer to access anything within the program’s range of allowable addresses (called the address space). In some operating systems and on some processors, each program has access to the entire machine’s address space. On those systems, a malicious programmer can use pointer arithmetic to wreak havoc in other programs.


NOTE:  If you’re an experienced C or C++ programmer, you may ask, “Won’t I miss pointer arithmetic?” Most pointer arithmetic is used to get efficient access to character strings or other arrays. Java supports strings and arrays as explicit classes, with efficient methods to get at their contents. If you use these built-in methods, chances are you’ll never miss pointer arithmetic.

Another technique commonly used by malicious programmers is to deliberately overflow an array. Suppose a programmer defines an array of characters named myString to have 128 bytes. The locations myString[0] through myString[127] are reserved for use by the program. By accessing myString[128] and beyond, the program is reading and writing outside its assigned bounds. You can get away with that in C or C++, but in Java array accesses are checked at runtime. The program will not be allowed to access myString[] outside the range 0 to 127. Not only does this bounds-checking close a security hole, it also prevents one common source of program defects.

Strings are also immutable—after you’ve made a character string, no one can change it (although you can extract substrings and put them together to make new strings). By requiring that strings be immutable, Java’s designers closed another security hole and prevented still more common programming errors.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.