7.1 Running Untrusted Code
Recall
the Server example of Chapter 5. That generic server class dynamically loaded
and ran Service implementations. Suppose that you
are a system administrator in charge of the Server
program, and that you don't trust the programmers
who are developing the Service implementations;
you're afraid that they'll
accidentally (or maliciously) include damaging code in their
Service classes. Java makes it easy to run these
untrusted classes with access-control mechanisms in place, to prevent
them from doing anything they shouldn't.Access control in Java is performed by the
SecurityManager and
AccessController classes. When a security manager
has been registered, Java checks with it every time it is asked to
perform any operation that might be restricted, such as reading or
writing a file or establishing a network connection. In Java 1.2 and
later, the SecurityManager class uses the
AccessController class to perform these
access-control checks, and the AccessController in
turn refers to a Policy file that describes
exactly which Permission objects are granted to
what code.As of Java 1.2,
it is quite simple to run code under the watchful eye of a security
manager. Simply run the Java interpreter using the
-D option to set the
java.security.manager property. For example, to
run the Server class under a security manager,
start it like this:
% java -Djava.security.manager je3.net.Server -control password 4000
When you do this, both the Server class and the
control service class it loads are subject to the access-control
checks of a security manager that uses the system's
default security policy.
If you try running
Server using the default security policy shipped
by Sun, the server will fail when the first client attempts to
connect to it, and you'll see the following message:
java.security.AccessControlException:
access denied (java.net.SocketPermission 127.0.0.1:1170 accept,resolve)
This message tells you that the security manager has not allowed your
Server class to accept a network connection from
the client. The reason is that the default security policy is too
restrictive for our server. Fortunately, there is an easy way to
allow the server to accept connections. Create a file with the
following contents (except replace the directory name with the name
of the directory where you have your classes installed) and name it
Server.policy :
// These lines grant permissions to any code loaded from
the directory shown.
// Edit the directory to match the installation on your system.
// On Windows systems, change the forward slashes to
double backslashes: "\\".
grant codeBase "file:/home/david/Books/JavaExamples2/Examples" {
// Allow the server to listen for and accept network connections
// from any host on any port > 1024
permission java.net.SocketPermission "*:1024-", "listen,accept";
};
Once you've created the
Server.policy file, run the server class again
but add another -D option to specify that the
interpreter should use this policy file:
% java -Djava.security.manager -Djava.security.
policy=Server.policy je3.net.Server -control password 4000
When you use this command line, the Java interpreter takes the
default security policy and augments it with the policy specified on
the command line. Note that if you use = = instead
of = in the command line, the interpreter ignores
the default policy and uses only the policy you've
specified. Our Server.policy file should work
either way.The moral of the story is that if you write a Java application and
want people who don't trust you to run it, you
should figure out exactly what kind of restricted actions it takes
and develop a policy file for it. Then your users can study the
policy file to see what permissions the application requires. If
they're willing to grant those permissions to your
code, they can run your program using the -D
options shown earlier, secure in the knowledge that your code
can't take any dangerous actions other than those
explicitly allowed by your policy file.To fully understand
Java's access control mechanisms,
you'll want to read about the
java.security.Permission class and its many
subclasses. You should also read about the
java.security.Policy class. To be able to create
policy files of your own, you'll want to read about
the policytool program that ships with the Java
SDK from Sun. See Java in a Nutshell. If you
want to edit policy files by hand (which is often easiest), see the
security documentation that comes with the SDK for details on the
file format.