15.3 Security Architecture and Security Policy

The Java platform builds a security architecture on top of the protections promised by the JVM. A security architecture is a way of organizing the software that makes up the Java platform so that potentially harmful operations are isolated from unprivileged code but available to privileged code. Most code is unprivileged; only carefully selected pieces of code are privileged to perform potentially dangerous operations. The security architecture is responsible for making sure that unprivileged code does not masquerade as privileged code.

The core of the Java platform security architecture under Java platforms 1.0 and 1.1 is the SecurityManager class.[1] This class decides which pieces of code can perform certain operations and which cannot. Collectively, these decisions are called the security policy. The security policy is enforced by the Java platform classes, which check the SecurityManager before proceeding with any operations under the control of the SecurityManager.

[1] On the Java 2 platform, the core of the security architecture is shifted to a class called AccessController, which falls outside the scope of this book. See http//java.sun.com for more information.

Only one instance of the SecurityManager can be installed, and once it is installed it cannot be removed. It is called the security manager. By default, there is no security manager, and all operations are permitted. The class java.lang.System is responsible for ensuring that there is only one security manager. It provides the static methods getSecurityManager and setSecurityManager to get and set the security manager.

The SecurityManager class has a set of methods that are called by the Java platform code before proceeding with certain potentially harmful operations. These methods throw a SecurityException if the operation is forbidden. If no exception is thrown, then the caller may assume that the operation is permitted, and it can proceed with the operation. Table 15.1 describes the operations that are checked by the SecurityManager in the Java 1.02 platform.

The security manager uses a variety of factors to determine whether an operation is permitted or not. These factors include the source of the code attempting the operation and the preferences of the user (discussed further in sections 15.3.2 and 15.3.3). First we present an example of how the security architecture and the security policy interact.

Table 15.1. Security checks
Method Operation checked Called by
checkAccept (String host, int port) Accepting a socket connection from host on port ServerSocket.accept
checkAccess (Thread g) Modifying the thread g

Thread.stop

Thread.suspend

Thread.resume

Thread.setPriority

Thread.setName

Thread.setDaemon

checkAccess (ThreadGroup g) Modifying the thread group g

ThreadGroup.<init>

ThreadGroup.setDaemon

ThreadGroup.setMaxPriority

ThreadGroup.stop

ThreadGroup.resume

ThreadGroup.destroy

checkConnect (String host, int port) Opening a socket to host on port Socket.connect
checkCreateClassLoader() Creating a class loader ClassLoader.<init>
checkDelete(String file) Deleting a file File.delete
checkExec(String cmd) Creating a subprocess Runtime.exec
checkExit(int status) Exiting the JVM Runtime.exit
checkLink(String lib) Loading a library

Runtime.load

Runtime.loadLibrary

checkListen(int port) Listening at a port Socket.listen
checkPackageAccess (String package) Attempting to access package ClassLoader.loadClass
checkPackageDefinition (String package) Defining a class in package ClassLoader.loadClass
checkPropertiesAccess() Reading or writing properties

System.getProperties

System.setProperties

checkPropertyAccess (String property) Reading the property named property System.getProperty
checkRead (FileDescriptor fd) Reading from the file descriptor fd FileInputStream.<init>
checkRead(String file) Reading from the file named file FileInputStream.<init>
checkSetFactory() Setting a socket factory

ServerSocket

SetSocketFactory

checkWrite (FileDescriptor fd) Writing to a file descriptor FileOutputStream.<init>
checkWrite(String f) Writing to a file named file FileOutputStream.<init>

15.3.1 Example

The security architecture demands that before a file is opened for reading, the security manager will be checked to see whether the code requesting the file is allowed to open the file. This is a sensible policy, since the ability to read files gives a program access to potentially important and confidential information.

The most important ways to read files are through the FileInputStream or FileReader classes in the java.io package. These classes include native methods that are implemented in a machine-dependent way to interact with the computer's file system. Before these methods can be used, an instance of FileInputStream or FileReader must be constructed. Following the security architecture, all the publicly accessible constructors of FileInputStream and FileReader begin with a call to the checkRead method of SecurityManager:

 /** Open the file named filename */ public FileInputStream(String filename) throws      FileNotFoundException {    SecurityManager security = System.getSecurityManager();    // If a security manager is present, check it.    if (security != null)       security.checkRead(name);    // Open the file named filename; code omitted } 

The system's security manager is found by calling System.getSecurityManager(). There may not be a security manager installed, in which case the FileInputStream is free to open the file. If the security manager has not been established, then any code may set it. Secure systems, like web browsers, install a security manager before any applets are loaded.

If a security manager is present, then its checkRead method determines whether or not the code that called the constructor is allowed to read the file. How it decides this is a matter of the security policy of the particular system. If it decides that the read is not allowed, then a SecurityException is thrown.

This is where the JVM's promises become important. If an exception is thrown from checkRead, it will not be caught in the body of the constructor, causing the constructor to terminate abnormally. Since the constructor did not complete normally, the FileInputStream object is not constructed. If the code attempts to use the object before it has been constructed, then the verification algorithm rejects the program.

If the checkRead method returns normally, then the FileInputStream constructor also returns normally. Now that the FileInputStream object is constructed, all the public methods of FileInputStream, including read, may be invoked on it. The methods don't need to check for permission again, since the existence of the object implies that permission was granted.

15.3.2 Basic Applet Security Policy

For the writers of web browsers, security is of tremendous concern, since a malicious or mistaken applet could cause problems for many, many web surfers. For this reason, the Java applet security policy is very restrictive. The security manager discriminates between two kinds of classes: system classes (loaded by the JVM automatically) and applets (loaded by a custom class loader from over the network). The web browser implements its own security manager, which subclasses SecurityManager. Let's call it the AppletSecurityManager.

The AppletSecurityManager can ascertain the source of the applet by looking at the applet's class loader. Each class maintains a permanent association with its class loader. Anybody can find out which class loader loaded the class by invoking getClassLoader, a method of Class. Since Class is final, the verification algorithm ensures that the method getClassLoader cannot be overridden, so it is not possible for a class to lie about its class loader. The class loader can track information about the source of the applet.

The security manager needs to know which class is invoking the operation. For example, suppose an applet called NastyApplet tries to create a FileInputStream so that it can read the system's password file. In order to do that, it must call the constructor for FileInputStream, or the verification algorithm will reject the applet before it gets a chance to run. As shown in section 15.3.1, the constructor for FileInputStream calls checkRead in the security manager. The Java stack now looks like this:

Method Class Class loader
checkread AppletSecurityManager none
<init> FileInputStream none
attack NastyApplet AppletClassLoader
run NastyApplet AppletClassLoader

The SecurityManager provides the method currentClassLoader, which looks down the execution stack for the first method that comes from a class that was loaded by a class loader. Since AppletSecurityManager and FileInputStream are part of the browser itself, they are loaded without any class loader. The SecurityManager looks down the stack until it finds the run method from NastyApplet, which was loaded by AppletClassLoader.

The policy of the web browser is that no applet may try to read a file. The web browser's security policy is implemented by the class AppletSecurityManager. Part of the definition of AppletSecurityManager is

 class AppletSecurityManager extends SecurityManager {    public void checkRead(String name) throws SecurityException    {       ClassLoader loader = currentClassLoader();       if(loader instanceof AppletClassLoader)          throw new SecurityException("file.read");    } } 

Since the class loader is an AppletClassLoader, a security exception is thrown. It is not caught in the constructor for FileInputStream, so that method does not terminate normally. The FileInputStream is therefore invalid and may not be used to read any files. Security has been preserved.

15.3.3 More Sophisticated Policies

The security policy of the basic class loader, while effective at preventing security problems, is too tight for much work to get done, since it's not possible for an applet to save work or read previously written files.

A more sophisticated policy might allow applets to read and write files in a certain sandbox area: all files beginning with a certain absolute path would be permitted, all others denied. In some browsers, the system properties acl.read and acl.read.default control the sandbox area. If the user had configured acl.read as /sandbox, then a word processing applet would be permitted to read /sandbox/Letter.doc but the NastyApplet would not be allowed to read /etc/passwd.

Even this seemingly safe idea has some potential problems. The NastyApplet might try to fool the system by opening /sandbox/../etc/passwd, which names the password file on some systems. This is easily prevented by checking for relative references like "..", but it gives some idea of the sort of thing security developers must consider. This sort of potential security problem is beyond the domain of the JVM itself.

Another kind of security policy allows some code more trust than others. An applet programmer may cryptographically sign the bytecodes that make up the applet. The cryptographic signature makes it possible to determine whether the applet has been altered after it has been signed, since the signature is made from the original bytecodes that have been encrypted with the programmer's private key. Use of the programmer's public key allows the applet user to ascertain the source of the signature. Since the programmer's private key should be truly private, the signature uniquely identifies that programmer as the source of the code.

To make these more sophisticated security policies possible, the standard Java platform version 1.1 and later contain code in the java.security package to provide the code necessary for doing encryption, decryption, and signature verification. The classes in this package were designed to prevent applets from interfering with them, and they depend on the promises of the JVM to ensure that the cryptographic routines are not tampered with.



Programming for the Java Virtual Machine
Programming for the Javaв„ў Virtual Machine
ISBN: 0201309726
EAN: 2147483647
Year: 1998
Pages: 158
Authors: Joshua Engel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net