Chapter 8. Security I—execution

  • Introduction—RMI and security managers—Applets—Clients—Servers—System properties—Policy files—Granting AllPermission

In this chapter

So far in this book we have seen how to define a remote interface, and how to construct simple RMI servers and clients. If we want to construct a large RMI application, we need to consider some issues relating to security.

This chapter describes the interaction of RMI and the Java Security Model.[1] For more information about security across networks and secure protocols such as the Secure Sockets Layer, refer to Chapter 16.

Introduction

The Java Security Model constrains the actions permitted to Java code according to its source—where the code came from. The Security Model is activated by installing a “security manager”, either an instance of java.lang.SecurityManager or a derivation of it; for example:

System.setSecurityManager(new SecurityManager());

This statement is usually located early in the main procedure of an application: the same effect can be obtained by specifying the -Djava.security.manager option on the Java command line. Once a security manager is installed, it checks all the external actions of the JVM, and a large number of internal actions, to see if the code which invoked the action has permission to perform it. If the check fails, a java.lang.SecurityException is thrown.

RMI and security managers

RMI clients and servers may run under the control of a Java security manager. They must run under a security manager to be able to acquire code from an RMI codebase. An RMI codebase is a source, usually network-wide, of Java class files and associated resources. For more information about codebases and code mobility in general, refer to Chapter 9.

Once a security manager has been installed, any attempt to install another one (or to set it to null) is itself subject to security permission-checking; if the caller does not have the permission RuntimePermission(“setSecurityManager"), or if the security manager rejects all attempts to replace it, a SecurityException is thrown.

This chapter describes the Java 2 Security Model introduced in JDK 1.2. The earlier Java 1 “sandbox” security model was much less fine-grained: it had no provision for treating classes from different sources differently, and was not extensible by the user. The “sandbox” model also required you to enable or disable different security-related actions by implementing your own security manager class, rather than just specifying your security policy in a text file as in Java 2.

Applets

A Java applet, whether running in a browser or in the Sun appletviewer, runs under the control of a security manager. In browsers whose Java version is prior to Java 2 (JDK 1.2), permissions are configured in a browser-dependent way which is beyond the scope of this book. In browsers compatible with Java 2, permissions must be granted by a policy file, which can be configured by the Java policytool.

Applet viewers and Web browsers impose the following restrictions on an applet:

  • it cannot load libraries or define native methods

  • it cannot ordinarily read or write files on the host that is executing it

  • it cannot make network connections except to the host that it came from, and sometimes not even to that host

  • it cannot start any program on the host that is executing it

  • it cannot read certain system properties

  • windows that it brings up look different from windows that an application brings up.

This list is reproduced from information on Sun's Java Web site and is not intended to be definitive. Consult the documentation of your target browser(s) for definitive information on applet security.

These restrictions mean that an applet can only be a client of RMI servers located at the host from which the applet was loaded, and that an applet can usually not be an RMI server.

Clients

A stand-alone RMI client must run under a security manager if it is to acquire code from a codebase.

Servers

RMI servers need not run under a security manager unless they upload client code or are activatable.

Non-activatable servers

From the point of view of RMI, a non-activatable server doesn't really need to run under a security manager unless it intends to upload code from codebases other than its own, i.e. codebases provided by clients or other servers. However, you may find it desirable for application design reasons to install a security manager, even if this condition does not apply.

Activatable servers

As we will see in Chapter 10, activatable servers are always under the control of a security manager.

System properties—security

Java 2 security is controlled by the system properties shown in Table 8.1.

It is an instructive exercise to run your application with the property setting java.security.debug = access, to see exactly what permissions it requires in the course of its execution.

Table 8.1. Security-related system properties in Java 2

Property Values Comments
java.security.debug all access[,failure]

The value “all” causes a trace of all security-checking actions.

The value “access” traces all SecurityManager.checkPermission results.

The value “access,failure” causes a stack trace and domain dump before throwing any SecurityException.

For a list of all possible values for this property, use java.security.debug=help.

java.security.manager no value Installs the default security manager java.lang.SecurityManager before the application is executed.
java.security.policy URL Specifies an alternative security policy file.

Security exceptions and the actions that lead to them can be “debugged” by setting the system property java.security.debug=access,failure. This causes a trace to be output on any SecurityException showing exactly what required permission had not been granted, along with a stack trace and a dump of the applicable security domain (to be discussed later in this chapter).

Note that SecurityException is a runtime exception, so the Java compiler won't force you to catch it, and it can be thrown by all sorts of operations in the Java Class Libraries. In a security-managed environment, you should make arrangements to catch this exception at appropriate places: at the least, in the main procedure of an application, or the init, start and stop methods of an applet; and in the run methods of all Threads and Runnables, or an override of ThreadGroup.uncaughtException.

Policy files

Permissions are managed in a policy file—a text file which by default is named “java.policy”, and is managed by the policytool program provided with the JDK and JRE. While we won't discuss in detail how to run the policy tool program or manage policy files, we will discuss various permissions that an RMI server or client can expect to require.

A policy file consists of one or more protection domains, each of which is associated with a code source and contains zero or more permission entries. The relationships among these entities are illustrated in Figure 8.1.

Policy file elements and relationships

Figure 8.1. Policy file elements and relationships

A sample policy file is shown in Example 8.1.

Example 8.1. Sample policy file

// grant everyone the following permissions
grant {
       permission java.net.SocketPermission "*:80", "connect";
}

// permissions for SupplierA at domain SupplierA.com
grant signedBy "SupplierA", codeBase "http://codebase.supplierA.com/" {
      permission java.net.SocketPermission "localhost:80", "listen";
      permission java.net.SocketPermission "*.rmi.supplierA.com:1024-",
           "connect";
      permission java.awt.RuntimePermission "queuePrintJob";
}

Protection domain

In Java 2, a protection domain is a set of permission entries granted to a code source.

Code source

A code source is a codebase (a URL) associated with zero or more digital certificates. If there are one or more certificates, the code source is considered to be signed, otherwise it is considered to be unsigned. Any given Java class is uniquely associated with a code source, and so with zero or more certificates, and hence with zero or more “signers”—known entities which it may or may not be reasonable to trust.

Permission entry

A permission entry is composed of a name, an optional actions list, and an optional target.

The general idea is that you supply your application in a signed JAR file as a code source, and supply a policy file which contains a protection domain for that code source, listing the permissions granted to the application.

Detailed discussion of policy files and signed JAR files is beyond the scope of this book: see the JDK documentation for further information.

Table 8.2 lists some permissions that RMI servers and clients may require. This list is not exhaustive. Use java.security.debug = access to discover which permissions your application or applet needs.

Note

RMI itself does not require any of these permissions, as it uses “privileged blocks” to perform the necessary operations. This can easily be verified by running the RemoteEcho example with the -Djava.security.manager setting on both server and client.

Table 8.2. Permissions for RMI

Permission Actions Target Comments
AWTPermission accessEventQueue Required if the application peeks, reads, or posts to the AWT event queue.
AWTPermission showWindowWithoutWarningBanner Disables the “Java Applet Window” warning. Applications with GUIs—other than applets—should be granted this permission.[a]
FilePermission read write execute delete Required if your application reads files outside its own directory structure, or if your application writes, executes, or deletes files.[b]
PropertyPermission read write java.rmi.* sun.rmi.* Required if the application reads or writes RMI system or implementation properties.[c]
RuntimePermission getClassLoader Required if the application calls this API..
RuntimePermission loadLibrary.awt loadLibrary.fontmanager Required if the application has a GUI.
RuntimePermission loadLibrary.math Required if the application uses the java.lang.Math class.
RuntimePermission loadLibrary.net Required if the application uses Sockets itself, e.g. in a client or server socket factory.
RuntimePermission queuePrintJob Required if the application creates print jobs.
RuntimePermission readFileDescriptor May be required if the application does I/O.
RuntimePermission setFactory Required if the application uses Socket.setSocketImplFactory, RMISocketFactory .setSocketFactory, or other setFactory methods in the JDK.
RuntimePermission writeFileDescriptor May be required if the application does I/O.
SerializablePermission enableSubclassImplementation enableSubstitution May be required if the application does its own serialization (other than RMI marshalling and unmarshalling) and uses a custom ObjectInputStream or ObjectOutputStream.
SocketPermission accept host:port Required by RMI servers to specify addresses and ports from which they may accept connections.[d]
SocketPermission connect host:port Required by RMI clients to specify hosts, domains, and ports to which they may connect.
SocketPermission listen localhost:1024- Applications exporting RMI servers need this permission. It is granted in the default JDK 1.3 java.policy file.[e]
SocketPermission resolve host:port This permission is implied by any of the accept, connect, or listen permissions, so there is little need to specify it explicitly

[a] .This permission is intended to distinguish applet windows from non-applet windows; however, JDKs 1.2.2 and 1.3 display the warning on non-applet windows as well as applet windows unless this permission is granted. Applying this behaviour to non-applets appears to be a bug.

[b] You should grant these permissions very sparingly, i.e. only as widely as required. If possible, you should design your application so that it only reads files within its own directory structure.

[c] .If your application modifies RMI system properties—or indeed any system properties—after installing a security manager, it will also need permission for the “write” action. Instead of granting these permissions, you may prefer to read or modify the properties before installing the manager.

[d] .After a connection has been accepted, but before the resulting Socket has been returned to the caller of ServerSocket.accept, a check is made to see if the caller has permission to accept from the remote host/port pair to which the socket is connected. This is in addition to the prior check on the local host/port pair, which is done when the socket entered the “listening” state (i.e. when the ServerSocket was constructed).

[e] .On Unix-like systems, the ports below 1024 are only available to privileged programs

A privileged block is a block of code executed via the AccessController.doPrivileged method. Such a block asserts that its own codebase alone should be used to compute the permissions granted to it, rather than its entire class-loading context. For further information, see the JDK documentation.

Granting AllPermission

Some of the Sun RMI tutorials mention the technique of granting an AllPermission to your codebase, to let it do anything, rather than specifically enumerating each permission your application needs. The tutorials present this technique to simplify the lessons. This “no safety-belt” policy is a solution to the initial problem of how to get a programming sample running quickly.

The JDK 1.3 documentation states: “This permission should be used only during testing, or in extremely rare cases where an application or applet is completely trusted and adding the necessary permissions to the policy is prohibitively cumbersome".[2] You may also consider it reasonable to grant AllPermission to a single protection domain which is signed, or whose code source is a local file: codebase. You should not grant AllPermission to protection domains introduced by “grant {” in the policy file, or the codebase ALL in the policy tool, which apply to any codebase or signer (including the case of no signer—unsigned code).

Unless you are going to grant AllPermission in production, you will probably find it easier overall not to use it in development either. Instead, you should add specific permissions to your application's policy file as the application itself indicates that they are required, carefully considering each one before doing so. The alternative is to leave all permission investigation to a “big bang” at the end of development: this process runs the risk of overlooking required permissions, unless your testing is completely exhaustive. You should certainly have a permission-testing phase but you shouldn't rely on it alone to discover all required permissions: this is a development task.

The development of an application's security policy merits its own design and review process. A single custodian of the policy file should probably be appointed in a development effort of any size.



[1] The Java Security Model is specified in the JDK documentation, and described in Gong, Inside Java 2 Platform Security.

[2] JDK 1.3 online documentation for java.security.AllPermission.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.209.131