Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.59 MB, 702 trang )
• Classes stored in the local file system (usually found using the
CLASSPATH system environment variable)
• Classes retrieved from external sources such as from a Web server
Clearly, we would not want to overwrite a trusted JVM class with an identically
named class from a Web server since this would undermine the entire Java
security model. For instance, the SecurityManager class is responsible for a
large part of the JVM run-time security and is a trusted local class; consider
what would happen to security if the SecurityManager could be replaced by a
class loaded from a remote site. The class loader must therefore ensure that
trusted local classes are loaded in preference to remote classes where a
name clash occurs.
Secondly, where classes are loaded from Web servers, it is possible that
there could be a deliberate or unintentional collision of names (although the
Sun Java naming conventions exist to prevent unintentional name collisions).
If two versions of a class exist and are used by different applets from different
Web sites, then the JVM, through the auspices of the class loader, must
ensure that the two classes can coexist without any possibility of confusion
occurring.
The class loader must protect the boundaries of the trusted class packages.
The core Java class libraries that ship with the JVM reside in a series of
packages. Within the Java programming language, it is possible to give
special access privileges to classes that reside in the same package; thus, a
class which is part of the java.lang package, for instance, has access to
methods and fields within other classes in the java.lang package which are
not accessible to classes outside of this package.
If it were possible for a programmer to add his or her own classes to the
java.lang package, then those classes would also have privileged access to
the core classes. This would be an exposure of the JVM and consequently
must not be allowed. The class loader must therefore ensure that classes
cannot be dynamically added to the various core language packages.
The JVM may have many class loaders operating at any point in time, each of
which is responsible for locating and loading classes from different sources.
6.1.1 Loading Classes from Trusted Sources
There is one class loader, the primordial class loader, which is a built-in part
of the JVM; that is, its code is written in the same language the JVM is written
in (typically C) and is an integral part of the JVM. It is also known as the
internal, or null, or default class loader. The primordial class loader is the root
146
Java 2 Network Security
of the class loader delegation hierarchy (see 6.1.4.2, “How the Design Is
Implemented” on page 152 for details on delegation) and is responsible for
loading the trusted classes of the Java run time.
Classes loaded by the primordial class loader are regarded as special insofar
as they are not subject to verification prior to execution; that is, they are
assumed to be well formed, safe Java classes. In the Java Development Kit
(JDK) 1.1, these are the JVM core classes plus any classes which can be
found using the CLASSPATH system environment variable. Obviously, if
would-be attackers could somehow introduce a malicious class into the
CLASSPATH of a JVM they could cause serious damage1.
In Java 2, this exposure is minimized by removing the core class path
information from the CLASSPATH environment variable and subjecting all but
the core classes to verification and the security policy. It is also possible to
subject the core classes to verification using the -verify option of the java
command or the -J-verify option of the appletviewer command, for example.
Of course, this does not affect that part of the JVM implemented in the native
language.
The core classes in Java 2 are located by using a JVM internal property,
sun.boot.class.path. The value of this property is called the boot class path
and is formed internally from install information or can be specified by the
java command option -Xbootclasspath, which becomes -J-Xbootclasspath for
the appletviewer command (see 3.4.1, “Boot Class Path” on page 84).
6.1.2 Loading Classes from Untrusted Sources
Along with bounding the scope of implicitly trusted classes to just the Java
core classes, Java 2 removed the responsibility for the loading of local user
classes from the primordial loader. Now, at JVM startup, the application class
path information is copied from the CLASSPATH environment variable into
the JVM internal property java.class.path and this is used to start an instance
of java.net.URLClassLoader, a new class loader class extending the new
class java.lang.SecureClassLoader (described in 6.1.3, “Beyond What the
JVM Provides” on page 148). This instance is given a list of file-based URLs
generated from CLASSPATH, which it will use to locate and load local user
classes. This class loader instance will also verify the class file and set up the
associated protection domain. The value of java.class.path can also be set on
the command line using the option -classpath (or -cp). This will override the
CLASSPATH environment setting.
1 This was the basis of one of the attacks discovered by the Secure Internet Programming team at Princeton University.
Their attack, Slash and Burn , is described more fully in Java Security, Hostile Applets, Holes and Antidotes, Gary
McGraw and Ed Felten.
The Class Loader and Class File Verifier
147
From a trust viewpoint, logically in between the fully trusted core classes (no
policy file permission entries required) and the completely untrusted
application classes (explicit policy file permissions required) are classes of
the new extension class framework (see 3.4.2, “Extensions Framework” on
page 86). This framework allows for the installation of Java archive files in a
specific extensions directory pointed to by the JVM internal property
java.ext.dirs. The default setting for java.ext.dirs is ${java.home}/lib/ext and
can be set using the -Djava.ext.dirs=somevalue command line option. A
Java class called ExtClassLoader is responsible for loading installed
extensions. ExtClassLoader is an inner class of the sun.misc.Launcher class.
ExtClassLoader is also know as extensions class loader.
These classes are in the search order after core classes, but before
application classes. They are subjected to verification and policy, but the
default policy is AllPermissions (see 4.1.1, “The Class Loader” on page 110).
6.1.3 Beyond What the JVM Provides
Application writers (including JVM implementers) are at liberty to build more
class loaders to handle the loading of classes from different sources such as
the Internet, an intranet, local storage or perhaps even from ROM in an
embedded system. These class loaders are not a part of the JVM; rather,
they are part of an application running on top of the JVM.
In JDK 1.1, application implementers were required to implement any class
loading requirements beyond what the primordial loader would provide by
extending the java.lang.ClassLoader abstract class. The most obvious
example of this is in the context of a Web browser which must load classes
from an HTTP server. The browser’s class loader that does this is generally
known as the applet class loader and is itself a Java class which knows how
to request and load other Java class files from a Web server across a TCP/IP
network. The JDK’s Applet Viewer includes a reference implementation called
AppletClassLoader, which is shipped with the JDK in the sun.applet package
and has been the basis for most browsers’ class loaders.
Starting with Java 2, the Java run time includes an implementation of
ClassLoader called SecureClassLoader. SecureClassLoader implements the
basic security related requirements of class loading. It handles checking with
the security manager, calling the class file verifier, linking of the class and
setting up the protection domain. Its constructor is protected.
SecureClassLoader is meant to be the basis for the development of other
class loaders. To extend this, there is also a general purpose loader included
in the SDK, called URLClassLoader, in the java.net package, which is a
subclass of SecureClassLoader. URLClassLoader adds the ability to find and
148
Java 2 Network Security
load class files from a list of file and HTTP-based URLs. URLClassLoader
should meet most of the requirements an application may have for loading
class files. And if not, developers should now develop their own loaders by
subclassing one of these two classes, instead of the ClassLoader abstract
class, to benefit from the function and security built into SecureClassLoader.
It should be clear that there can be many types of class loaders within a Java
environment at any one time. In addition, there may be many instances of a
particular type of class loader operating at once.
To summarize:
• There will always be one and only one primordial class loader. It is part of
the JVM, like the execution engine.
• There will be one instance of the URLClassLoader which was created at
JVM initialization. This instance is responsible for loading user classes
from the local file system specified in the java.class.path property, which is
set from the CLASSPATH environment variable.
• In a Web browser environment, there will be at least one additional class
loader, which is responsible for loading the applet classes.
• There will be zero or more additional class loader types. These should
extend one of the class loader classes: URLClassLoader,
SecureClassLoader, or least desirably the ClassLoader abstract class.
There are, of course, other choices.
• For each additional ClassLoader type, there will be zero or more instances
of that type created as Java objects.
Let’s look at this last point more closely.
Why would we want to have multiple instances of the same class loader
running at any one time?
To answer this question we need to examine what class loaders do with a
class once it has been loaded.
Every class present in the JVM has been loaded by one and only one class
loader. For any given class, the JVM remembers which class loader was
responsible for loading it. If that class subsequently requires other classes to
be loaded, the JVM uses the same class loader to load those classes.
This gives rise to the concept of a name space, the set of all classes which
have been loaded by a particular instance of a class loader. Within this name
space, duplicate class names are prohibited. More importantly, there is no
The Class Loader and Class File Verifier
149
cross name space visibility of classes; a class in one name space (loaded by
a particular class loader instance) cannot access a class in another name
space (loaded by a different class loader instance).
Returning to the question Why would we want to have multiple instances of
the same class loader running at any one time?, consider the case of the
applet class loader. It is responsible for loading classes from a Web server
across the Internet or intranets. On most networks (and certainly the Internet)
there are many Web servers from which classes could be loaded and there is
nothing to prevent two webmasters from having different classes on their sites
with the same name.
Since a given instance of a class loader cannot load multiple classes with the
same name, if we didn’t have multiple instances of the applet class loader, we
would very quickly run into problems when loading classes from multiple
sites. Moreover, it is essential for the security of the JVM to separate classes
from different sites so that they cannot inadvertently or deliberately cross
reference each other. This is achieved by having classes from separate Web
sites loaded into separate name spaces, which in turn is managed by having
different instances of the applet class loader for each site from which applets
are loaded.
6.1.4 The Class Loading Process
We now look at the class loading process. First, we will look at it from a
design viewpoint. Second, we show how the design is implemented in Java 2
class loaders and how it should be implemented by an application needing to
develop a class loader in Java 2. Keep in mind, we are assuming a security
manager.
6.1.4.1 What Is Supposed to Happen
In this section, we look at some of the design aspects of the class loading
architecture in Java 2. In other words, we describe what is supposed to
happen from the viewpoint of the Java architects.
1. When a class is referenced, the JVM execution environment invokes the
instance of the class loader associated with the requesting program to
locate and load the referenced class.
2. The class loader first checks to see if the requested class has been
previously loaded by itself.
• If so, the loader checks with the security manager to see if the program
has permission to access the requested class.
• If it does not have permission, a security exception is generated.
150
Java 2 Network Security
• If the program has permission, the loader returns a reference to the
existing class object.
• If not already loaded, the class loader checks with the security
manager to see if this program has permission to create the requested
class.
• If it does not, a security exception is generated.
• If the program has permission, the loader first tries to find the
requested class in the core Java API followed by any JVM
extensions. The difference between the core and extension classes
is that the extension classes are subject to verification and the
security policy in effect. This step prevents the JVM’s core and
extension classes from being replaced by classes from another
location. If the class is found, the class is loaded into the class area
and a reference to the class object is returned. The core and
extension classes should be loaded using the JVM’s built-in class
loader, the primordial class loader.
3. If we have come to this point without finding the requested class, this
means that the requested class has not been found in a trusted location.
Therefore, the class loader will load the class as an array of bytes to be
verified by the class file verifier before constructing a class object. The
loader will look through the application class path before going to the
network to locate the class. The application class path is found in the JVM
internal property java.class.path, which is set from the CLASSPATH
environment variable, or the -classpath (or -cp) argument of the java
command.
4. The class file verifier is responsible for making sure that class files contain
only legal Java bytecodes and that they behave properly (for example,
they do not attempt to underflow or overflow the stack, forge illegal
pointers to memory or in any other way subvert the JVM). Details of this
are in 6.2, “The Class File Verifier” on page 168. If verification fails, a
security exception is generated.
5. If the bytecodes pass verification, a class object is created and a
protection domain is associated with the class for subsequent resource
authorization checking. The class is then linked by resolving any
references to other classes within it. This may result in additional calls to
the class loader to locate and load other classes.
6. Next, static initialization of the class is performed; that is, static variables
are defined and static initializers are run.
7. Finally, the class is available to be executed.
The Class Loader and Class File Verifier
151
6.1.4.2 How the Design Is Implemented
Every class loader, being just another Java class itself, is loaded by a class
loader, with one exception, the primordial class loader. This forms a run-time
parent-child hierarchical relationship between class loader objects with the
primordial class loader at the root. This relationship is the basis for the
delegation model, which is the recommended implementation model for all
class loaders starting with Java 2. That is, every class loader upon entry
should immediately invoke (delegate the request to) the class loader which
loaded it, its parent class loader. This will cause a call back all the way to the
JVM’s internal loader which will stop this apparent foolishness and attempt to
load the class from the bootstrap class path or the extension class path. Only
if all ancestors fail should the child try to locate and load the class.
To illustrate how this works, consider the PointlessButton applet (see Figure
17 on page 37). As a reminder, PointlessButton uses a second class,
jamjar.examples.Button, which represents a push button on the browser
display. Pushing the button results in nothing happening except a display is
updated to inform you how many times nothing has happened to date.
In this example, we will work on a Web browser, called
MyFavoriteWebBrowser. MyFavoriteWebBrowser just happens to implement
a Java 2 style class loader, which extends URLClassLoader and is called
Java2StyleAppletClassLoader. When MyFavoriteWebBrowser encounters the
PointlessButton applet in a Web page the following sequence of events
occurs:
1. MyFavoriteWebBrowser finds the