Cover | Table of Contents
java.applet.Applet class and is
written as a series of callbacks, while an application can be any
class that has a static method called main().
When this programming distinction is important, we'll use the
terms "applet" and "application" as
appropriate. But we'll typically use the term
"program" to refer to the Java code that we're
running.JavaRunner technique and the
Launcher technique. While both allow you to run
an application securely, the examples in this chapter do not provide
any security. We'll fill in the security pieces bit by bit,
while we flesh out the security story. At that point, we'll
show how to run Java applications securely.
main() method. Consider this application that
reads the file specified by a command-line argument:public class Cat {
public static void main(String args[]) {
try {
String s;
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
while ((s = br.readLine()) != null)
System.out.println(s);
} catch (Exception e) {
System.out.println(e);
}
}
}piccolo% java Cat /etc/passwd
root:x:0:1:0000-Admin(0000):/:/usr/bin/csh
daemon:x:1:1:0000-Admin(0000):/:
bin:x:2:2:0000-Admin(0000):/usr/bin:
...private: The entity can only be accessed by code
that is contained within 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.
Vector v = new Vector(); String s = (String) v;
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.Class object itself to carry
its signature with it). Hence, one of the keys to writing a secure
Java application is to understand the role of the class loader and to
write (or at least use) a secure class loader.java.io classes to determine that one
case should fail while the other case should succeed. That
differentiation is the by-product of the class loader: the class
loader allows the security manager to find out particular information
about the class, which allows the security manager to apply the
correct security policy depending on the context of the request. When
we discuss the security manager, we'll discuss the specific
mechanics by which this can be achieved. For now, it is only
important to keep in mind that the class loader is the piece of the
Java architecture that is able to make this distinction. Since it
loaded the class, it knows if the class came from the network (i.e.,
the class is part of the applet and should not be trusted) or if the
class came from the local filesystem (i.e., the class is part of the
browser and should be trusted). It also knows if the class was
delivered with a digital signature, and the exact location from which
the class was loaded. All these pieces of information may be used by
the security manager and access controller to establish a security
policy.CLASSPATH. If that succeeds,
the class loader returns. This ensures that classes within the Java
API will not be superseded by classes loaded from the network (or
other location).findSystemClass() method) that handles this
step. In 1.2, a class loader must delegate to another class loader to
find classes that are on the CLASSPATH and call
the findSystemClass() method to find classes
that are in the core API.Class object is constructed from the
bytecodes. In the process, the methods defining the class are
created. In Java 1.1 and later, this process also ensures that the
name in the class file matches the name that the class loader thought
it was asked to load.ClassLoader
class (and all its subclasses) that accomplishes this:ClassNotFoundException is thrown if the class
cannot be found.loadClass() method. Once the
Class object has been constructed, there are
three ways in which a method in the class can be executed:main()
method of a Java application once the initial class has been loaded,
but this is not generally a technique used by Java applications.newInstance()
method of the
Class class, but only if the class has an
accessible constructor that requires no arguments. Once the object
has been constructed, methods with well-known signatures can be
executed on the object. This is the technique that a program like
appletviewer uses: it loads the initial class of
the applet, constructs an instance of the applet (which calls the
applet's no-argument constructor), and then calls the
applet's init() method (among other
methods).JavaRunner program.JavaRunner
program:public class JavaRunner implements Runnable {
ClassLoader class, or you can extend the
SecureClassLoader class. The second choice is
preferred, but it is not an option for Java 1.1. If you're
programming in 1.2, you may choose to use the URL class loader rather
than implementing your own, but the information in this section will
help you understand the security features of the URL class loader. In
this section, then, we'll look at how to implement both default
and secure class loaders.ClassLoader
class
(java.lang.ClassLoader). Since the
ClassLoader class is
abstract, it is necessary to subclass it to
create a class loader.
name and, if indicated by the
resolve variable, ensure that the class is
resolved. If the class is not found, this method should throw a
ClassNotFoundException. This method is abstract
in 1.1, but not in 1.2. In 1.2, you typically do not override this
method.loadClass() method is passed a fully
qualified class name (e.g., java.lang.String or
com.xyz.XYZPayrollApplet), and it is expected to
return a class object that represents the target class. If the class
is not a system class, the loadClass() method is
responsible for loading the bytes that define the class (e.g., from
the network).ClassLoader class that a class loader can use to
help it achieve its task.appletviewer or by a Java-enabled browser.
However, there are other extensions to the class loader that are
often useful.appletviewer-type programs where the classes are
to be loaded from the network. This is good as far as it goes, but
let's delve a little more into the security issues that
surround that class loader.CODEBASE
specified in the applet's HTML tag. There are other reasons why
an applet can only make a network connection to its
CODEBASE (which we'll discuss in Chapter 4), but one of the reasons is contained in the
discussion we outlined above: because classes loaded by the same
class loader are considered to be in the same package, and an applet
that loaded classes from multiple sites could run the risk of classes
from different sites interfering with each other.
loadClass() method, it first
calls the loadClass() method of the delegate. If
that succeeds, the class returned by the delegate will ultimately be
returned by this class. If that fails, the class loader then uses its
original logic to complete its task:public Class loadClass(String name) {
Class cl;
cl = delegate.loadClass(name);
if (cl != null)
return cl;
// else continue with the loadClass() logic
}
null.CLASSPATH. That class
loader is the class loader that will be used to load the first class
in your application (i.e., the JavaRunner class
in our example).CLASSPATH. If the application will reference any
other classes that are part of the CLASSPATH,
you will be unable to find them unless you use the delegation model
of class loading: the JavaRunner program in Chapter 6.CLASSPATH is
considered trusted, and a class that is loaded from a class loader is
considered untrusted.CLASSPATH. However, this applies only when
certain command-line arguments are present; in the default method of
loading applications, items from the CLASSPATH
are generally considered trusted.CLASSPATH from performing operations that are
normally permitted to classes loaded from the filesystem. A security
manager can be as simple or as sophisticated as its author desires,
with the result that the security manager can enforce a simple binary
yes-or-no policy for operations, or it can enforce a very
specialized, very detailed policy. This is true of all security
managers in all versions of Java, though as we'll see in Chapter 5, one of the prime benefits of Java 1.2 is that
it makes it much easier to achieve fine-grained security policies.System class that are used to work with the
security manager itself:null if no security manager is in place).
Once obtained, this object can be used to test against various
security policies.SecurityException.getSecurityManager() method to retrieve the
security manager and invoke an operation on it. Setting the security
manager is a predictably simple operation:public class TestSecurityManager {
public static void main(String args[]) {
System.setSecurityManager(new SecurityManagerImpl());
...do the work of the application...
}
}setSecurityManager() method is written in such a
way that it can only be called once. Once a particular security
manager has been installed, that security manager will be used by
every other class that runs in this virtual machine. Once the policy
is established, it cannot be changed (although the policy itself
might be very fluid).SecureClassLoader
class (and its subclasses) are
responsible for creating and manipulating these code source objects.CodeSource class
(java.security.CodeSource
) has a few interesting methods:null.equals() method for
the URL of the objects returns true) and the
array of certificates is equal (that is, a comparison of each
certificate in the array of certificates will return
true).
Permission class (see later in this
chapter). One code source implies another if it contains all the
certificates of the parameter and if the URL of the parameter is
implied by the URL of the target.CodeSource class.
When we discussed the SecureClassLoader class in
Chapter 3, we showed that the
defineClass() method expected a
Permission class
(java.security.Permission). The
Permission class itself is an abstract class
that represents a particular operation. The nomenclature here is a
little misleading, because a permission object can reflect two
things. When it is associated with a class (through a code source and
a protection domain), a permission object represents an actual
permission that has been granted to that class. Otherwise, a
permission object allows us to ask if we have a specific permission.Permission class represents
one specific permission. A set of permissions—e.g., all the
permissions that are given to classes signed by a particular
individual—is represented by an instance of the
Permissions class
(java.security.Permissions). As developers and
administrators, we'll make extensive use of these classes, so
we'll need to investigate them in depth.FilePermission; an object to create a window
will have a type of AWTPermission; permission to
use the XYZ company payroll application would have a type of
XYZPayrollPermission.FilePermission has a name that is the name of
the file to be accessed; an AWTPermission to
create a window has a name of
showWindowWithoutWarningBanner; permission to
access a particular employee's payroll record would have the
name of that employee. Names are often based on
wildcards, so that a single file permission object may represent
permission to access several files, and so on.Policy class
(java.security.Policy).
checkProperty()
method of the security manager. By default, this succeeds only if you
already have been granted a security permission with the name of
getPolicy or setPolicy (as
appropriate). There's a bootstrapping issue involved when
setting the policy, since granting permissions requires the policy to
have been set. Hence, the initial policy is typically set by a class
in the core API, as those classes always have permission to perform
any operation.Policy class:Policy class, a
protection domain is one grant entry in the file. A protection domain
is an instance of the ProtectionDomain class
(java.security.ProtectionDomain
) and is constructed as follows:
defineClass()
method. A protection domain is assigned
to a class depending upon one of the following cases:defineClass() method accepts a protection
domain as a parameter. In this case, the given protection domain is
assigned to the class. This case is typically unused, since that
method exists in only the ClassLoader class and
not in the SecureClassLoader class.defineClass() method accepts a code source
as a parameter. In this case, the
getPermissions() method of the
SecureClassLoader is used to determine the
protection domain for the code source. By default, this just uses the