Methods of the Security Manager

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. The real point of this section is so that you can know which methods of the core Java API are affected by the security manager and to give you some background on why these choices were made.

When we discuss the methods below, we speak of them in terms of trusted and untrusted classes. A trusted class is a class of the core Java API or a class that has been granted explicit permission to perform the operation in question.

You’ll note that the methods of the security manager correspond fairly well to the set of default permissions that we listed in Chapter 2. In fact, the basic implementation of each method of the security manager is to test to ensure that each active protection domain has permission to perform the desired operation.

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 first of these methods succeeds if the current protection domain has been granted the runtime permission with the name readFileDescriptor. The other methods succeed if the current protection domain has a file permission with a name that matches the given file and an action of read.

public void checkWrite(FileDescriptor fd)
public void checkWrite(String file)

Check whether the program is allowed to write the given file. The first of these methods succeeds if the current protection domain has been granted the runtime permission with the name writeFileDescriptor. The second succeeds if the current protection domain has a file permission with a name that matches the given file and an action of write.

public void checkDelete(String file)

Check whether the program is allowed to delete the given file. This succeeds if the current protection domain has a file permission with a name that matches the given file and an action of delete.

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 it 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

Called By

Rationale

checkRead(  )
File.canRead(  )

Test if the current thread can read the file.

FileInputStream(  )
RandomAccessFile(  )

Constructing a file object requires that you read the file.

File.isDirectory(  )
File.isFile(  )

Determining whether a file object is an actual file or a directory requires that you read the file.

File.lastModified(  )

Determining the modification date requires that you read the file’s attributes.

File.length(  )

Determining the length requires that you read the file’s attributes.

File.list(  )

Determining the files in a directory requires that you read the directory.

checkWrite(  )
File.canWrite(  )

Test if the current thread can write the file.

FileOutputStream(  )
RandomAccessFile(  )

To construct a file object, you must be able to write the file.

File.mkdir(  )

To create a directory, you must be able to write to the filesystem.

File.renameTo(  )

To rename a file, you must be able to write to the directory containing the file.

File.createTempFile(  )

To create a temporary file, you must be able to write the file.

checkDelete(  )
File.delete(  )

Test if the current thread can delete a file.

File.deleteOnExit(  )

Test if the current thread can delete the file when the virtual machine exits.

If you carefully considered the list of methods in the table 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.

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. Untrusted classes loaded from the classpath cannot, by default, open any sockets.

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, and 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-2). 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.

A typical firewall configuration

Figure 4-2. 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 by default restricted from creating server sockets.[5] 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.

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. This succeeds if the current protection domain has a socket permission with a name that matches the host and port and an action of connect.

public void checkListen(int port)

Check if the program can create a server socket that is listening on the given port. The protection domain must have a socket permission where the host is localhost, the port range includes the given port, and the action is listen.

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. The protection domain must have a socket permission where the host and port match the parameters to this method and an action of accept.

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). This succeeds if the current protection domain has a socket permission with a host that matches the given address, a port range of all ports, and an action list of connect and accept.

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 program could install a socket factory so that the sockets it uses all have different semantics, such as sockets that send tracing information when they write data. The current protection domain must carry a runtime permission with the name setFactory.

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

checkConnect(  )
DatagramSocket.send(  )
DatagramSocket.receive(  )
    (Deprecated)
MulticastSocket.send(  )
Socket(  )

Test if the untrusted class can create a client-side connection.

checkConnect(  )
DatagramSocket.getLocalAddress(  )
InetAddress.getHostName(  )
InetAddress.getLocalHost(  ) 
InetAddress.getAllByName(  )

Test if the untrusted class can see any hosts on the local network.

checkListen(  )
DatagramSocket(  )
MulticastSocket(  )
ServerSocket(  )

Test if the untrusted class can create a server-side socket.

checkMulticast(  )
DatagramSocket.send(  )
DatagramSocket.receive(  )
MulticastSocket.send(  )
MulticastSocket.receive(  )
MulticastSocket.joinGroup(  )
MulticastSocket.leaveGroup(  )

Test if the untrusted class can operate on a multicast socket.

checkAccept(  )
ServerSocket.accept(  )
DatagramSocket.receive(  )

Test if the untrusted class can accept a server connection.

checkSetFactory(  )
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 from 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.[6]

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 instance, you could use a socket factory to provide sockets that always perform encryption. 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.

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

checkCreateClassLoader(  )
ClassLoader(  )

Class loaders are protected since they provide information to the security manager.

checkExec(  )
Runtime.exec(  )

Other processes might damage the user’s machine.

checkLink(  )
Runtime.load(  )
Runtime.loadLibrary(  )

Don’t let untrusted code import native code.

checkExit(  )
Runtime.exit(  )

Don’t let untrusted code halt the virtual machine.

checkExit(  )
Runtime.runFinalizersOnExit(  )

Don’t let untrusted code change whether finalizers are run.

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. As a result, the class loader 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. To succeed, the current protection domain must have a runtime permission with the name createClassLoader.

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.[7] To succeed, the current protection domain must have a file permission with a name that matches the given command and an action of execute.

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.

To succeed, the current protection domain must have a runtime permission with the name loadLibrary.<lib>.

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).

When you install a security manager via the command-line argument, all code (trusted or not) is able to exit the virtual machine. In the appletviewer or the Java Plug-in, the current protection domain must have the runtime permission named exitVM in order for this call to succeed.

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 used when you write your own permission classes, as we’ll examine in Chapter 5. It is also used directly by the Java API when it needs to test for runtime permissions. This method succeeds if the current protection domain has been granted the given permission.

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 virtual machine). 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 possibly 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. This call succeeds if the current protection domain has a runtime permission with the name modifyThread.

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). This call succeeds if the current protection domain has a runtime permission with the name modifyThreadGroup.

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. By default, a thread is able to manipulate any other thread except for threads in the root thread group; it is able to manipulate any thread group except for the root thread group.

Table 4-4. Security Manager Methods Protecting Thread Access

Method

Called By

Rationale

checkAccess(Thread g)
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.

checkAccess(ThreadGroup g)
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.

getThreadGroup(  )
Thread(  )

Threads of untrusted classes must belong to specified groups.

checkPermission(Permission p)
Thread.stop(  )

Stopping a thread could corrupt state of the virtual machine.

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.

The getThreadGroup( ) method can be used to create a hierarchy of thread groups. One popular use of this method is to segregate applets loaded from different sites into their own thread group; in a server, it could be used to segregate the threads assigned to different clients into different thread groups. Doing so requires some cooperation with the class loader since it forms a natural boundary between different applets or different clients. However, a full hierarchy of thread groups does not mesh well with Java’s default thread permission model, so we won’t discuss that option in the main text. In Appendix D, we discuss the implementation of a different security manager that uses this notion of a thread group hierarchy.

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.

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

checkPrintJobAccess(  )
Toolkit.getPrintJob(  )

Untrusted classes can’t initiate print jobs.

checkSystemClipboardAccess(  )
Toolkit.getSystemClipboard(  )

Untrusted classes can’t read the system clipboard.

checkAwtEventQueueAccess(  )
EventQueue.getEventQueue(  )

Untrusted classes can’t manipulate window events.

checkPropertiesAccess(  )
System.getProperties(  )
System.setProperties(  )

Untrusted classes can’t see or set system properties.

checkPropertyAccess(  )
System.getProperty(  )

Untrusted classes can’t get a particular system property.

checkPropertyAccess(  )
Locale.setDefault(  )

Can’t change the locale unless the user.language property can be read.

checkPropertyAccess(  )
Font.getFont(  )

Can’t get a font unless its property can be read.

checkTopLevelWindow(  )
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 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.

In order to succeed, the current protection domain must have an AWT permission with the name queuePrintJob.

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 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. To succeed, the current protection domain must have an AWT permission of accessClipboard.

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.

To succeed, the current protection domain must carry an AWT permission of accessEventQueue. The default security manager implementation is overridden by the Java Plug-in and appletviewer, which allow applets access to these methods but filter out events from other applet codebases.

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.

To succeed, the current protection domain must carry a property permission. If a key is specified, then the name of the property permission must include the given key and have an action of read. Otherwise, the name of the property permission must be “*” and the action must be read and write.

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. Theoretically, 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; no popular implementations do that. In order for this method to return true, the current protection domain must carry an AWT permission with the name showWindowWithoutWarningBanner.

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

checkMemberAccess(  )
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.

checkPackageAccess(  )
Not called

Check if the untrusted class can access classes in a particular package.

checkPackageDefinition(  )
Not called

Check if the untrusted class can load classes in a particular package.

checkSecurityAccess(  )
Identity.setPublicKey(  )
Identity.setInfo(  )
Identity.addCertificate(  )
Identity.removeCertificate(  )
IdentityScope.setSystemScope(  )
Provider.clear(  )
Provider.put(  )
Provider.remove(  )
Security.insertProviderAt(  )
Security.removeProvider(  )
Security.setProperty(  )
Signer.getPrivateKey(  )
Signer.setKeyPair(  )

Untrusted classes cannot manipulate security features.

public void checkMemberAccess(Class clazz, int which)

In Chapter 3, 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 cannot actually access those variables or call those methods). All classes are allowed to inspect any other class and find out about its public variables and methods. All classes loaded by the same class loader are allowed to inspect all of each other’s variables and methods. Otherwise, the current protection domain must carry a runtime permission with a name of accessDeclaredMembers.

The default implementation of this method is very fragile. Unlike all other methods that we’ll look at, it is a logical error to override this method and then call super.checkMemberAccess( ).

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, only trusted classes are allowed to perform any of these security-related operations. 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 how the security package uses this method in more depth.

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.

Notice 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, the checkPackageDefinition( ) method is never called and the checkPackageAccess( ) method is called only for packages listed in the package.access property within the java.security file. If you write a class loader, you may call it as we indicate in Chapter 6. To succeed, the current protection domain must have a runtime permission with the name defineClassInPackage.+<pkg> or accessClassInPackage.+<pkg>.

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 other public and protected methods of the SecurityManager class that we have not examined in this chapter; those methods are generally only used when you implement your own security manager without using the access controller, so we will defer their discussion to Appendix D. In the next chapter, we’ll discuss how the security manager is usually implemented.



[5] Technically, untrusted classes by default can create a server socket, since the default policy file allows all classes to perform the listen action. Once created, however, the server socket must accept a connection on the socket, and that action is by default denied.

[6] On the other hand, there’s a good chance the outside web server already has that information, since our browser sent along a hostname and other information when it retrieved the file to begin with. If our request passed through a firewall or proxy server, there’s a chance that some of this information was prevented from passing to the outside web server, but that’s not necessarily the case either.

[7] The separate process would not need to be written in Java, of course, so there would be no security manager around to enforce the prohibition about deleting files.

Get Java Security, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.