4.3. Using the Security Manager
We're now going to examine the public methods of the security
manager so that we may understand how the security manager is used by
applications and by the Java API.
4.3.1. Setting a 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. This
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
SecurityException.
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:
Class Definition
public class TestSecurityManager {
public static void main(String args[]) {
System.setSecurityManager(new SecurityManagerImpl());
...do the work of the application...
}
}
However, there's an important detail here: the
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).
This fact has two important ramifications. First, as the author,
it's up to you to write a security manager that embodies all
the security policies you want your Java application to have. Second,
in a Java-enabled browser, the security manager is always set as the
browser initializes itself. This makes it impossible for an
applet to set the security
manager--it must live with the policy established by the author
of the browser. This, of course, is a crucial feature of the security
manager: since the security manager is responsible for fencing in the
applet, it would be a catastrophe if the applet could change the
security manager and hence the security policies of the browser.
The real significance of this last point, however, is that it is up
to the developer of a browser to set the security
policy. There is no absolute
security policy that is common to every Java-enabled browser; each
company that supports one is free to develop its own security manager
and, accordingly, the security policies of that browser.
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.
When we discuss the rationale for each of the methods in the
SecurityManager class, we'll discuss them
from the point of view of untrusted classes. For now, consider an
untrusted class as one loaded from the network (i.e., as part of an
applet), while a trusted class is one that has been loaded from the
filesystem through the user's CLASSPATH
(including the classes that are part of the Java-enabled browser
itself).
4.3.2. Methods Relating to File Access
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 last
method in this list is not used by the Java API itself.
-
public void
checkWrite(FileDescriptor fd)
-
public void checkWrite(String file)
-
Check whether the program is allowed to write the given file.
-
public void
checkDelete(String file)
-
Check whether the program is allowed to delete the given file.
Interestingly, although as developers we tend to think of other file
operations--such as creating a file or seeing when the file was
last modified--as being distinct operations, as far as security
is concerned, the Java API considers all operations to be either
reading, writing, or deleting.
Table 4-1 lists the Java API interaction with the
checkRead(), checkWrite(),
and checkDelete() methods, listing when and why
each check is invoked. In all the tables in this chapter, the syntax
may imply that the calling methods are all static, but that of course
is not the case: the entry File.canRead() means
the canRead() method invoked on an instance of
the File class.
This table lists only those classes that directly call the security
manager method in question. There may be many routes through the Java
API that lead to one of these checks; for example, when a
FileReader object is constructed, it will
construct a FileInputStream object, which will
result in a call to checkRead().
Table 4-1. Check Methods
Method
|
Calling Methods
|
Rationale
|
Class Definition
checkRead()
|
Class Definition
File.canRead()
|
Test if the current thread can read the file
|
|
Class Definition
FileInputStream()
RandomAccessFile()
|
Constructing a file object requires that you must be able to read the
file
|
Class Definition
|
Class Definition
File.isDirectory()
File.isFile()
|
Determining whether a file object is an actual file or a directory
requires that you must be able to read the file
|
Class Definition
|
Class Definition
File.lastModified()
|
Determining the modification date requires that you read the
file's attributes
|
Class Definition
|
Class Definition
File.length()
|
Determining the length requires that you read the files attributes
|
Class Definition
|
Class Definition
File.list()
|
Determining the files in a directory requires that you read the
directory
|
Class Definition
checkWrite()
|
Class Definition
File.canWrite()
|
Test if the current thread can write the file
|
Class Definition
|
Class Definition
FileOutputStream()
RandomAccessFile()
|
To construct a file object, you must be able to write the file
|
Class Definition
|
Class Definition
File.mkdir()
|
To create a directory, you must be able to write to the filesystem
|
Class Definition
|
Class Definition
File.renameTo()
|
To rename a file, you must be able to write to the directory
containing the file
|
|
Class Definition
File.createTemp-File()
|
To create a temporary file, you must be able to write the
file
|
Class Definition
checkDelete()
|
Class Definition
File.delete()
|
Test if the current thread can delete a file
|
|
Class Definition
File.deleteOnExit()
|
Test if the current thread can delete the file when the virtual
machine exits
|
By default, in most Java-enabled browsers, untrusted classes are not
allowed any sort of file access, for these reasons:
-
If an untrusted class is allowed to read an arbitrary file, it might
read your password file, or the data file from your tax preparation
program, or the temporary file containing an edit log of the
sensitive document you're working on.
-
If an untrusted class is allowed to write an arbitrary file, it might
overwrite data on your machine, essentially erasing the file. Worse,
it might insert a virus into an existing file (or create a new file
with a virus), with catastrophic results. Less damaging, but still a
problem, would be the ability for the applet to completely fill the
available disk space.
-
If an untrusted class is allowed to delete files, it could destroy
any data in your local filesystem.
Some Java developers consider this strict restriction on file access
unnecessarily draconian--they'd seek a compromise where at
least some access to some local files is possible. The types of
suggested compromises are things like:
-
Untrusted classes should be allowed access to the system's
temporary directory.
The problem with this is that other programs might have left
sensitive data in that directory. If I'm editing salary data on
my machine, I wouldn't want some untrusted class to come along
and see the edit log that exists in the system's temporary
directory.
-
A single directory could be set up for the exclusive use of untrusted
classes.
This does not prevent a bad untrusted class from accessing, erasing,
or corrupting the data files of other untrusted programs.
-
An individual directory could be set up for each applet (or for each
package of untrusted classes).
This would work in theory, but such a scheme would be unwieldy. It
also leaves potential attack routes for an applet. On the Internet,
one site can pretend to be another site by engaging in IP spoofing
(see the discussion in Section 4.1, "The Need for Authentication" in Chapter 7, "Introduction to Cryptography"); applets from such sites could read data from the original applet.
In addition, an applet could still fill the available disk space.
-
The user could be prompted before an untrusted class accessed a file.
This issue is less black-and-white. On the one hand, there's a
persuasive argument that computer users are pretty intelligent, and
they'll know whether or not a program should be allowed to
access the file in question. In the real world, however, there are
users who will not pay enough attention to such prompts and always
grant access, to the detriment of their system's security. You
may not have much sympathy for users on home computers who grant an
applet access to the data file of their financial package, but the
user on a corporate or campus network who allows an applet access to
his or her password file harms other users of the network as
well.
Nonetheless, as with all policies enforced by the security manager,
it is up to the author of a particular program (or web browser) to
establish the policy the security manager will enforce. Hence, while
Netscape Navigator, Internet Explorer, and HotJava all have a default
policy that prevents untrusted classes from all file access, some of
them allow the user to configure a different policy. HotJava and the
JDK's appletviewer, for example, allow the
user to create a set of directories in which applets can read and
write files, and some versions of Internet Explorer allow the user to
grant file access to all untrusted classes.
There is one exception to the rule about file access: applets that
are loaded from a CODEBASE that specifies
file as its protocol (e.g.,
file:/myapplets) are allowed to read (but not
create or delete) files in the CODEBASE
directory (and any of its subdirectories). This is required to allow
the applet to load other resources--audio files, images, as well
as other classes--in the same manner in which it would load
those resources through an HTTP-based URL.
If you carefully considered the list of methods in the tables above,
you were probably surprised not to see an obvious method to check:
the actual read() or
write() methods of any of the
File classes. The assumption here is that a
trusted class is responsible for determining the security policy
associated with any particular File object; if
the trusted class decides that it is okay for an untrusted class to
perform I/O on a particular File*Stream object,
then it is free to deliver that object to the untrusted class, and
the untrusted class is free to read or write to that object. This
implementation also allows for much greater efficiency: if the
program had to check with the security manager every time it called
the read() or write()
methods, I/O performance would drastically suffer.
4.3.3. Methods Relating to Network Access
Network
access in Java is always accomplished by opening a network socket,
whether directly through the Socket class or
indirectly through another class like the URL
class. An untrusted class can only (by default)
open a socket to the machine from which it was actually downloaded;
typically, this is the location given by the
CODEBASE tag in the HTML for the browser page
containing the applet or--in the absence of such a tag--the
web server for the page. In either case, the machine in question is a
web server, so we'll use that terminology in this discussion.
This restriction on untrusted
classes is designed to prevent two types of attack. The first attack
concerns a rogue applet using your machine for malicious purposes by
connecting to a third machine over the network. The canonical
description of this attack is an applet that connects to the mail
server on someone else's machine and sends people on that
machine offensive email from your address. There are more severe
attacks possible with this technique, however--such an applet
could use a connection from your machine to break into a third
computer; auditors on that third computer will think the break-in
attempts are coming from you, which can cause you all sorts of legal
problems.
The second sort of attack concerns network information on your local
network that you might not want to be broadcast to the world at
large. Typically, computers at corporations or campuses sit behind a
firewall so that users on the Internet cannot access those computers
(see Figure 4-1). The firewall allows only certain
types of traffic through (e.g., HTTP traffic), so that users on the
local network can access the Internet, but users on the Internet
cannot glean any information about the local network.
Figure 4-1. A typical firewall configuration
Now consider what happens if an applet downloaded onto a machine on
the local network can connect to other machines on the local network.
This allows the applet to gather all sorts of information about the
local network topology and network services and to send that
information (via HTTP, so that it will pass through the firewall)
back out onto the Internet. Such an opportunity for corporate spying
would be very tempting to would-be hackers. Worse, if the applet had
access to arbitrary network services, it could break into the local
HR database and steal employee data, or it could break into a network
file server and steal corporate documents. Hence, applets (and
untrusted classes in general) are prevented from arbitrary network
access.
Network sockets can be logically divided into two classes:
client
sockets and server sockets. A client socket is responsible for
initiating a conversation with an existing server socket; server
sockets sit idle waiting for these requests to come from client
sockets. Untrusted classes are often restricted from creating server
sockets. Normally, this is not a problem: since an applet can only
talk to its web server, it could only answer requests from that
machine--and the applet can already open a connection to that
machine at will; there's no algorithmic or logistic reason why
an operation between the applet and the web server cannot always
start with the applet as the client. In situations where the applet
is allowed to open client sockets to other machines, however, this
reasoning doesn't apply, and the ability to create a server
socket is often granted in such situations (and, sometimes, in all
situations).
The security manager uses the following methods to check network
access:
-
public void
checkConnect(String host, int port)
-
public void checkConnect(String host, int port, Object context)
-
Check if the program can open a client socket to the given port on
the given host. The second form of this method is never called
directly from the Java API.
-
public void
checkListen(int port)
-
Check if the program can create a server socket that is listening on
the given port.
-
public void
checkAccept(String host, int port)
-
Check if the program can accept (on an existing server socket) a
client connection that originated from the given host and port.
-
public void
checkMulticast(InetAddress addr)
-
public void checkMulticast(InetAddress addr, byte ttl)
-
Check if the program can create a multicast socket at the given
multicast address (optionally with the given time-to-live value).
-
public void
checkSetFactory()
-
Check if the program can change the default socket implementation.
When the Socket class is used to create a
socket, it gets a new socket from the socket factory, which typically
supplies a standard TCP-based socket. However, a socket factory could
be used to supply SSL-based sockets, or any other socket variant.
The instances where these methods are used and the rationale for such
uses are shown in Table 4-2.
Table 4-2. Security Manager Methods to Protect Network Access
Method
|
Called by
|
Rationale
|
Class Definition
checkConnect()
|
Class Definition
DatagramSocket.send()
DatagramSocket.receive()
MulticastSocket.send()
Socket()
|
Test if the untrusted class can create a client-side connection
|
Class Definition
checkConnect()
|
Class Definition
DatagramSocket.getLocalAddress()
InetAddress.getHostName()
InetAddress.getLocalHost()
InetAddress.getAllByName()
|
Test if the untrusted class can see any hosts on the local network
|
Class Definition
checkListen()
|
Class Definition
DatagramSocket()
MulticastSocket()
ServerSocket()
|
Test if the untrusted class can create a server-side socket
|
Class Definition
checkMulticast()
|
Class Definition
DatagramSocket.send()
DatagramSocket.receive()
MulticastSocket.send()
MulticastSocket.receive()
MulticastSocket.joinGroup()
MulticastSocket.leaveGroup()
|
Test if the untrusted class can operate on a multicast socket
|
Class Definition
checkAccept()
|
Class Definition
ServerSocket.accept()
DatagramSocket.receive()
|
Test if the untrusted class can accept a server connection
|
Class Definition
checkSetFactory()
|
Class Definition
ServerSocket.setSocketFactory()
Socket.setSocketFactory()
URL.setURLStreamHandlerFactory()
URLConnection.setContentHandlerFactory()
RMI.setSocketFactory()
|
Test if the untrusted class can alter the manner in which all sockets
are created
|
checkSetFactory()
|
HttpURLConnection.setFollowRedirects()
|
Test if the untrusted class can change redirection behavior
|
Some notes are in order. As in the case with file access, these
methods sometimes check operations that are logically different from
a programming view, but are essentially the same thing at a system
view. Hence, the checkConnect() method not only
checks the opening of a socket but also the retrieval of hostname or
address information (on the theory that to know the name of a host,
you need to be able to open a socket to that host). This last test
may seem somewhat odd--under what circumstances, you might
wonder, should an untrusted class not be able to know the name or
address of the machine on which it is running? Recall that we want to
prevent the outside world from knowing our network topology; this
includes the name and address of the user's machine as
well.[3]
There was a change in the default security policy supplied in 1.0 and
in 1.1 with respect to untrusted classes and server sockets (either
instances of class ServerSocket or datagram
sockets that received data from any source). In 1.0, untrusted
classes were typically not allowed to create a server socket at all,
which meant that the checkListen() and
checkAccept() methods always threw a security
exception when an applet attempted such an operation. In 1.1 and
later, untrusted classes are allowed to create a server socket so
long as the port number of that socket is greater than the privileged
port number on the machine (typically 1024). Note too that the
receive() method of the
DatagramSocket class in 1.2 now calls the
checkAccept() rather than the
checkConnect() method.
Some applet publishers consider it to
be very inconvenient to have to put both the applet and any network
services that the applet requires on the same machine (the
applet's web server). When you're configuring a network
of machines, it certainly is more natural to have a database server
that is separate from the web server; the scaling and flexibility
that such separation gives is the cornerstone of network computing.
Hence, an applet that is running on the browser shown in Figure 4-2 would consider it more convenient to access
the database server directly. Sites with this configuration may
therefore attempt to convince you to adjust your browser's
network connection policy so their applet will work in this
multitiered environment.
Figure 4-2. An untrusted class cannot directly connect to the database server
However, it's relatively trivial for applet publishers to set
up a proxy
service on their web server that forwards requests to the third
machine, so that the applet only connects to the web server while the
proxy service can connect to the third machine (e.g., the database
server). Such a configuration may not be ideal--there's
still a lot of traffic on the web server going through the
proxy--but it's an effective compromise.
The requirement to use a proxy should not prove onerous to
developers, either; it's common for network software providers
to deliver such proxies with their Java code. Many JDBC-driver
vendors, for example, provide such a proxy HTTP server that their
JDBC drivers can access. Writing a simple proxy from scratch for
other services is well within the grasp of good Java programmers.
Nonetheless, if in your view the reward of reduced network traffic
outweighs the security considerations behind preventing arbitrary
network access by untrusted classes, the Sun browsers (HotJava and
appletviewer) and some versions of Internet
Explorer allow you to configure them so that untrusted classes can
connect to any host on the network.
The
checkSetFactory() method of the security manager class is
responsible for arbitrating the use of several low-level aspects of
Java's network classes. Most of the tests made by this method
have to do with whether or not the untrusted class is allowed to
create some variety of socket factory. Socket factories are
classes that are responsible for creating sockets that implement a
particular interface while having a nonstandard feature: for example,
a Java server might want to encrypt all of its traffic, so it would
create and install a socket factory that creates only SSL-enabled
sockets. Predictably, untrusted classes cannot change the socket
factory in use.
This method is also used to determine whether the Java program will
automatically follow redirect messages when opening a URL. When a
Java program opens a URL, the server to which it is connected may
send back a redirect response (an HTTP response code of 3xx). Often,
browsers follow these redirects transparently to the user; in Java,
the programmer has the ability to determine if the redirection should
automatically be followed or not. An untrusted class is not able to
change whether redirection is on or off. The
HttpURLConnection class that uses this method is abstract,
so the actual behavior of this class may be overridden in a
particular implementation.
4.3.4. Methods Protecting the Java Virtual Machine
There are a number of methods in the
SecurityManager class that protect the integrity
of the Java virtual machine and the security manager. These methods
fence in untrusted classes so that they cannot circumvent the
protections of the security manager and the Java API itself. These
methods are summarized in Table 4-3.
Table 4-3. Security Manager Methods Protecting the Virtual Machine
Method
|
Called by
|
Rationale
|
Class Definition
checkCreateClassLoader()
|
Class Definition
ClassLoader()
|
Class loaders are protected since they provide information to the
security manager
|
Class Definition
checkExec()
|
Class Definition
Runtime.exec()
|
Other processes might damage the user's machine
|
Class Definition
checkExec()
|
Class Definition
System.setIn()
System.setOut()
System.setErr()
|
Don't let important messages be redirected away from the user
|
Class Definition
checkLink()
|
Class Definition
Runtime.load()
Runtime.loadLibrary()
|
Don't let untrusted code import native code
|
Class Definition
checkExit()
|
Class Definition
Runtime.exit()
|
Don't let untrusted code halt the virtual machine
|
Class Definition
checkExit()
|
Class Definition
Runtime.runFinalizers-OnExit()
|
Don't let untrusted code change if finalizers are run
|
Class Definition
checkPermission()
|
many
|
See if the current thread has been granted a particular permission
|
-
public void checkCreateClassLoader()
-
The distinction we keep mentioning between trusted and untrusted
classes is often based on the location from which the class was
loaded (i.e., if the class came from the filesystem or from the
network). As a result, the class loader we examined in Chapter 3, "Java Class Loaders" takes on an important role, since the security
manager must ask the class loader where a particular class came from.
The class loader is also responsible for marking certain classes as
signed classes. Hence, an untrusted class is typically not allowed to
create a class loader. This method is only called by the constructor
of the ClassLoader class: if you can create a
class loader (or if you obtain a reference to a previously created
class loader), you can use it.
-
public void checkExec(String cmd)
-
This method is used to prevent execution of arbitrary system commands
by untrusted classes--an untrusted class cannot, for example,
execute a separate process that removes all the files on your
disk.[4] In addition, this method is used to test whether a Java
program is able to redirect the standard input, output, or error
streams to another source--with the predictable result that
untrusted classes are not allowed to perform such redirection.
In Java 1.2, this method is no longer used to determine whether the
standard streams may be redirected. Redirection of those streams in
1.2 is determined instead by the
checkPermission() method.
-
public void checkLink(String lib)
-
System commands aren't the only code that is out of reach of
the security manager--any native (C language) code that is
executed by the virtual machine cannot be protected by the security
manager (or, in fact, by any aspect of the Java sandbox). Native code
is executed by linking a shared library into the virtual machine;
this method prevents an untrusted class from linking in such
libraries.
It may seem as if this check is very important. It is, but only to a
point: the programmatic binding from Java to C is such that Java code
cannot just call an arbitrary C function--the C function must
have a very specialized name that will not exist in an arbitrary
library. So any C function that the untrusted class would like to
call must reside in a library that you've downloaded and placed
on your machine--and if the program's author can convince
you to do that, then you don't really have a secure system
anyway, and the author could find a different line of attack against
you.
-
public void checkExit(int status)
-
Next, there is the continuing processing of the virtual machine
itself. This method prevents an untrusted class from shutting down
the virtual machine. This method also prevents an untrusted class
from changing whether or not all finalizers are run when the virtual
machine does exit. This means that an untrusted class--and in
particular, an applet--cannot guarantee that all the finalize
methods of all the objects will be called before the system exits
(which cannot be guaranteed in any case, since the browser can be
terminated from the operating system without an opportunity to run
the finalizers anyway).
-
public void checkPermission(Permission p)
-
public void checkPermission(Permission p, Object context)
-
Check to see if the current thread has the given permission. This
method is at the heart of the access controller, which we'll
explain in Chapter 5, "The Access Controller", where we'll also list
when it is called. The second form of this method is never used by
the Java API. The default for untrusted classes is to be given only a
few explicit permissions, which we'll also list in Chapter 5, "The Access Controller".
4.3.5. Methods Protecting Program Threads
Java depends heavily
on threads for its execution; in a simple Java program that uses
images and audio, there may be a dozen or more threads that are
created automatically for the user (depending on the particular
implementation of the VM). These are system-level threads responsible
for garbage collection, the various input and output needs of the
graphical interface, threads to fetch images, etc. An untrusted class
cannot manipulate any of these threads, because doing so would
prevent the Java virtual machine from running properly, affecting
other applets and possible even the browser itself.
The security manager protects threads with these methods:
-
public void
checkAccess(Thread g)
-
Check if the program is allowed to change the state of the given
thread.
-
public void checkAccess(ThreadGroup g)
-
Check if the program is allowed to change the state of the given
thread group (and the threads that it holds).
-
public ThreadGroup
getThreadGroup()
-
Supply a default thread group for newly created threads to belong to.
Table 4-4 shows the methods of the Java API that
are affected by the policy set in the
checkAccess() methods.
Table 4-4. Security Manager Methods Protecting Thread Access
Method
|
Called by
|
Rationale
|
Class Definition
checkAccess(Thread g)
|
Class Definition
Thread.stop()
Thread.interrupt()
Thread.suspend()
Thread.resume()
Thread.setPriority()
Thread.setName()
Thread.setDaemon()
Thread.setClassLoader()
Thread()
|
Untrusted classes may only manipulate threads that they have created
|
Class Definition
checkAccess(ThreadGroup g)
|
Class Definition
ThreadGroup()
ThreadGroup.setDaemon()
ThreadGroup.setMaxPriority()
ThreadGroup.stop()
ThreadGroup.suspend()
ThreadGroup.resume()
ThreadGroup.destroy()
ThreadGroup.interrupt()
|
Untrusted classes can only affect thread groups that they have created
|
Class Definition
getThreadGroup()
|
Class Definition
Thread()
|
Threads of untrusted classes must belong to specified groups
|
Class Definition
checkPermission(Permission p)
|
Class Definition
Thread.stop()
|
Stopping a thread could corrupt state of the virtual machine.
|
Most of the rationale behind these methods is straightforward: an
untrusted class can manipulate its own threads, and it can manipulate
threads that are in its thread group. This prevents an untrusted
class from suspending the threads responsible for loading images; for
example, those threads were not created by the untrusted class, and
so the untrusted class cannot affect them.
Threads
in a Java program are organized into a hierarchy (see Figure 4-3). In theory, the policy of the security
manager should also apply to this hierarchy such that threads may
only manipulate threads that are below them in the hierarchy. Hence,
the calculating thread really should not be able to manipulate the
state of the I/O reading thread--regardless of whether the
calculating thread is executing trusted code or untrusted code.
Similarly, the processing thread ought to be able to manipulate the
state of the I/O reading thread even if the code to do so is in an
untrusted class, since that implies that the untrusted class created
the processing thread and the I/O thread anyway.
Figure 4-3. A Java thread hierarchy
In practice, however, it does not work that way in Java 1.1: in that
release, by default each applet is given an individual thread group,
and the threads within that group can manipulate other threads within
that group without respect to any hierarchy. In Java 1.2, the default
is for the thread hierarchy to operate as expected.
Unlike the other public methods of the security manager, the
getThreadGroup() method is not responsible for
deciding whether access to a particular resource should be granted or
not, and it does not throw a security exception under any
circumstances. The point of this method is to determine the default
thread group that a particular thread should belong to. When a thread
is constructed and does not ask to be placed into a particular thread
group, the getThreadGroup() method of the
security manager is used to find a thread group to which the thread
should be assigned. By default, this is the thread group of the
calling thread, but a security manager can implement different logic
so that the thread hierarchy we've described above becomes
possible.
The getThreadGroup() method is only present in
Java 1.1 and subsequent releases. In Java 1.0 (and browsers built on
that release), thread security was generally non-existent: any thread
could manipulate the state of any other thread, and applets
weren't able to create their own thread groups. This additional
method provided the infrastructure by which security managers built
in Java 1.1 and later releases can implement the security policy that
we've described here.
In 1.2 the Thread class also calls the
checkPermission() method of the security manager
whenever the stop() method is called, since
stopping a thread is an inherently dangerous operation (which has led
the stop() method to become deprecated). For
backward compatibility, this permission is normally granted even to
untrusted classes, but an end user may change her environment so that
the security manager throws an exception whenever the
stop() method is called.
4.3.6. Methods Protecting System Resources
The Java-enabled browser has access to
certain system-level resources to which untrusted classes should not
be granted access. The next set of methods (outlined in Table 4-5) in the SecurityManager
class handles those system-level resources.
Table 4-5. Security Manager Protections of System Resources
Method
|
Called by
|
Rationale
|
Class Definition
checkPrintJobAccess()
|
Class Definition
Toolkit.getPrintJob()[5]
|
Untrusted classes can't initiate print jobs
|
Class Definition
checkSystemClipboardAccess()
|
Class Definition
Toolkit.getSystemClipboard()
|
Untrusted classes can't read the system clipboard
|
Class Definition
checkAwtEventQueueAccess()
|
Class Definition
EventQueue.getEventQueue()
|
Untrusted classes can't manipulate window events
|
Class Definition
checkPropertiesAccess()
|
Class Definition
System.getProperties()
System.setProperties()
|
Untrusted classes can't see or set system properties
|
Class Definition
checkPropertyAccess()
|
Class Definition
System.getProperty()
|
Untrusted classes can't get a particular system property
|
Class Definition
checkPropertyAccess()
|
Class Definition
Locale.setDefault()
|
Can't change the locale unless the
user.language property can be read
|
Class Definition
checkPropertyAccess()
|
Class Definition
Font.getFont()
|
Can't get a font unless its property can be read
|
Class Definition
checkTopLevelWindow()
|
Class Definition
Window()
|
Windows created by untrusted classes should have an indentifying
banner
|
-
public void checkPrintJobAccess()
-
Untrusted classes are not allowed
access to the user's printer. This is another example of a
nuisance protection; you wouldn't want a rogue applet sending
reams of nonsense data to your printer. This method is never actually
called by the standard Java API--it's up to the
platform-specific implementation of the AWT toolkit to call it.
Note that this doesn't prevent the user from initiating a print
action from the browser--it only prevents an applet from
initiating the print action. The utility of such a check is subtle:
the user always has to confirm the print dialog box before anything
is actually printed (at least with the popular implementations of the
AWT toolkit). The only sort of scenario that this check prevents is
this: the user could surf to www.EvilSite.org
and then to www.sun.com; although the applets
from EvilSite are no longer on the current page,
they're still active, and one of them could pop up the print
dialog. The user will associate the dialog with the
www.sun.com page and presumably allow it to
print--and when the EvilSite applet then prints out offensive
material, the user will blame the Sun page.
-
public void checkSystemClipboardAccess()
-
The
Java virtual machine contains a system clipboard that can be used as
a holder for copy-and-paste operations. Granting access to the
clipboard to an untrusted class runs the risk that a class will come
along, examine the clipboard, and find contents a previous program
left there. Such contents might be sensitive data that the new class
should not be allowed to read; hence, untrusted classes are prevented
from accessing the system clipboard. This restriction applies only to
the system clipboard: an untrusted class can still create its own
clipboard and perform its own copy-and-paste operations to that
clipboard. Untrusted classes can also share non-system clipboards
between them.
This method is also never actually called by the Java API; it's
up to the platform-specific implementation of the AWT toolkit to call
it.
-
public void
checkAwtEventQueueAccess()
-
Similarly, the Java virtual machine contains a system event queue
that holds all pending AWT events for the system. An untrusted class
that had access to such a queue would be able to delete events from
the queue or insert events into the queue. This protects against the
same sort of scenario we saw for printing--an applet on a
previously visited page could insert events into the queue which
would then be fed to an applet on the existing page.
Since this means that an untrusted class cannot get the system event
queue, it is unable to call any of the methods of the
EventQueue class--specifically the
postEvent() and peekEvent()
methods. Note, however, that an applet may still post events to
itself using the dispatchEvent() method of the
Component class.
-
public void
checkPropertiesAccess()
-
public void
checkPropertyAccess(String key)
-
The Java virtual machine has a set of
global (system) properties that contains information about the user
and the user's machine: login name, home directory, etc.
Untrusted classes are generally denied access to some of this
information in an attempt to limit the amount of spying that an
applet can do. As usual, these methods only prevent access to the
system properties; an untrusted class is free to set up its own
properties and to share those properties with other classes if it
desires.
Note that security managers are typically written to allow access to
some system properties based on the name of the property.
-
public boolean
checkTopLevelWindow(Object window)
-
Java classes, regardless of whether they are trusted or untrusted,
are normally allowed to create top-level windows on the user's
desktop. However, there is a concern that an untrusted class might
bring up a window that looks exactly like another application on the
user's desktop and thus confuse the user into doing something
that ought not be done. For example, an applet could bring up a
window that looks just like a telnet session and grab the
user's password when the user responds to the password prompt.
For that reason, top-level windows that are created by untrusted
classes have some sort of identifying banner on them.
Note that unlike other methods in the security manager, this method
has three outcomes: if it returns true, the
window will be created normally; if it returns
false, the window will be created with the
identifying banner. However, this method could also throw a security
exception (just like all the other methods of the security manager
class) to indicate that the window should not be created at all.
However, all the popular security manager implementations allow an
untrusted class to bring up a window, subject to the identifying
banner.
4.3.7. Methods Protecting Security Aspects
There are a number of methods
in the security manager that protect Java's idea of security
itself. These methods are summarized in Table 4-6.
Table 4-6. Security Manager Methods Protecting Java Security
Method
|
Called by
|
Rationale
|
Class Definition
checkMemberAccess()
|
Class Definition
Class.getFields()
Class.getMethods()
Class.getConstructors()
Class.getField()
Class.getMethod()
Class.getConstructor()
Class.getDeclaredClasses()
Class.getDeclaredFields()
Class.getDeclaredMethods()
Class.getDeclaredConstructors()
Class.getDeclaredField()
Class.getDeclaredMethod()
Class.getDeclardConstructor()
|
Untrusted classes can only inspect public information about other
classes
|
Class Definition
checkPackageAccess()
|
Class Definition
not called
|
Check if the untrusted class can access classes in a particular
package
|
Class Definition
checkPackageDefinition()
|
Class Definition
not called
|
Check if the untrusted class can load classes in a particular package
|
Class Definition
checkSecurityAccess()
|
Class Definition
Identity.setPublicKey()
Identity.setInfo()
Identity.addCertificate()
Identity.removeCertificate()
IdentityScope.setSystemScope()
Provider.clear()[6]
Provider.put()
Provider.remove()
Security.insertProviderAt()
Security.removeProvider()
Security.setProperty()
Signer.getPrivateKey()
Signer.setKeyPair()
Identity.toString()[7]
Security.getProviders()
Security.getProvider()
Security.getProperty()
|
Untrusted classes cannot manipulate security features
|
-
public void checkMemberAccess(Class clazz, int which)
-
In Chapter 2, "Java Language Security", we
examined the importance of the access modifiers to the integrity of
Java's security model. Java's reflection API allows
programs to inspect classes to determine the class's methods,
variables, and constructors. The ability to access these entities can
impact the memory integrity that Java provides.
The reflection API is powerful enough that, by inspection, a program
can determine the private instance variables and methods of a class
(although it can't actually access those variables or call
those methods). Untrusted classes are allowed to inspect a class and
find out only about its public variables and methods.
-
public void checkSecurityAccess(String action)
-
In the last half of this book, we'll be examining the details
of the Java security package. This package implements a higher-order
notion of security, including digital signatures, message digests,
public and private keys, etc. The security package depends on this
method in the security manager to arbitrate which classes can perform
certain security-related operations. As an example, before a class is
allowed to read a private key, this method is called with a string
indicating that a private key is being read.
Predictably, an untrusted class is not allowed to perform any of
these security-related operations, while a trusted class
is.[8] Although the
string argument gives the ability to distinguish what operation is
being attempted, that argument is typically ignored in present
implementations. As we discuss the features of the security package
itself, we'll examine more in depth how the security package
uses this method.
-
public void checkPackageAccess(String pkg)
-
public void checkPackageDefinition(String pkg)
-
These methods are used in conjunction with
a class loader. When a class loader is asked to load a class with a
particular package name, it will first ask the security manager if it
is allowed to do so by calling the
checkPackageAccess() method. This allows the
security manager to make sure that the untrusted class is not trying
to use application-specific classes that it shouldn't know
about.
Similarly, when a class loader actually creates a class in a
particular package, it asks the security manager if it is allowed to
do so by calling the checkPackageDefinition()
method. This allows the security manager to prevent an untrusted
class from loading a class from the network and placing it into, for
example, the java.lang package.
Note the distinction between these two methods: in the case of the
checkPackageAccess() method, the question is
whether the class loader can reference the class at all--e.g.,
whether we can call a class in the sun package.
In the checkPackageDefinition() method, the
class bytes have been loaded, and the security manager is being asked
if they can belong to a particular package.
By default, these methods are never called. If you write a class
loader, you should make sure that you call these methods as we
indicated in Chapter 3, "Java Class Loaders".
That's all the methods of the security manager class that are
used by the Java API to perform checks on certain operations. There
are two more public methods of the
SecurityManager class that we have not examined
in this section; even though those methods are public, they are
generally only used when you implement your own security manager, so
we will defer their discussion. Remember that the discussion we
followed in this chapter about the behavior of the system is based on
a default set of behaviors exhibited by popular Java-enabled
browsers--but since each browser is free to implement its own
security policies, your particular browser may have a variation of
the features we've just discussed.
| | |
4.2. Trusted and Untrusted Classes | | 4.4. Summary |
Copyright © 2001 O'Reilly & Associates. All rights reserved.
|