Java Examples In A Nutshell (3rd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java Examples In A Nutshell (3rd Edition) [Electronic resources] - نسخه متنی

O'Reilly Media, Inc

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








7.2 Loading Untrusted Code


Let's
continue our Server example. Suppose now that you
want to modify the server so that it can load
Service classes over the network from an arbitrary
URL. Suppose also that you want to give Service
classes the ability to read and write files from a
"scratch" directory on the local
system. You can accomplish this by writing a simple class that uses
URLClassLoader to load service classes and pass
them to an instance of the Server class. To make
it work, however, you also have to develop an appropriate security
policy file.

Example 7-1 shows
our SafeServer class. Like the original
Server class, this one expects a list of
Service classes and port numbers on the command
line. But the first command-line argument it expects is the URL from
which the service classes should be downloaded.

Example 7-1. SafeServer.java

package je3.security;
import je3.net.Server;
import java.io.*;
import java.net.*;
import java.security.*;
/**
* This class is a program that uses the Server class
defined in Chapter 5.
* Server would load arbitrary "Service" classes to
provide services.
* This class is an alternative program to start up a
Server in a similar
* way. The difference is that this one uses a
SecurityManager and a
* ClassLoader to prevent the Service classes
from doing anything damaging
* or malicious on the local system.
This allows us to safely run Service
* classes that come from untrusted sources.
**/
public class SafeServer {
public static void main(String[ ] args) {
try {
// Install a Security manager if the user didn't already install
// one with the -Djava.security.manager argument
if (System.getSecurityManager( ) == null) {
System.out.println("Establishing a security manager");
System.setSecurityManager(new SecurityManager( ));
}
// Create a Server object
Server server = new Server(null, 5);
// Create the ClassLoader that we'll use to load Service classes.
// The classes should be stored in the JAR file or the directory
// specified as a URL by the first command-line argument
URL serviceURL = new URL(args[0]);
ClassLoader loader =
new java.net.URLClassLoader(new URL[ ] {serviceURL});
// Parse the argument list, which should contain Service name/port
// pairs. For each pair, load the named Service using the class
// loader, then instantiate it with newInstance( ), then tell the
// server to start running it.
int i = 1;
while(i < args.length) {
// Dynamically load the Service class using the class loader
Class serviceClass = loader.loadClass(args[i++]);
// Dynamically instantiate the class.
Server.Service service =
(Server.Service)serviceClass.newInstance( );
int port = Integer.parseInt(args[i++]); // Parse the port #
server.addService(service, port); // Run service
}
}
catch (Exception e) { // Display a message if anything goes wrong
System.err.println(e);
System.err.println("Usage: java " + SafeServer.class.getName( ) +
" <url> <servicename> <port>\n" +
"\t[<servicename> <port> ... ]");
System.exit(1);
}
}
}


7.2.1 A Policy for SafeServer


The
SafeServer class creates and establishes a
SecurityManager even if the user
doesn't do this with the
-Djava.security.manager argument. This means that
the program is not able to run without a security policy that grants
it the permissions it needs. Example 7-2 shows a
policy file you can use to make it work.

There are a
couple of things to note about the
SafeServer.policy file. First, the policy file
reads system properties named service.dir and
service.tmp. These are not standard system
properties; they are properties that you must specify to the Java
interpreter when you run the SafeServer program.
service.dir specifies the directory from which the
service classes are to be loaded. Assume here that they are loaded
via a local file: URL, not through an
http: or other network URL. The
service.tmp property specifies a directory in
which the service classes are allowed to read and write temporary
scratch files. SafeServer.policy demonstrates a
syntax that replaces the name of a system property with the value of
that property. In this way, the security policy file can be made
somewhat independent of the installation location of the application.

Example 7-2. SafeServer.policy

// This file grants the SafeServer class the
permissions it needs to load
// Service classes through a URLClassLoader,
and grants the Service classes
// permission to read and write files in
and beneath the directory specified
// by the service.tmp system property.
Note that you'll need to edit the
// URL that specifies the location of the SafeServer class,
and that for
// Windows systems, you'll need to replace "/" with "\\"
// Grant permissions to the SafeServer class.
// Edit the directory for your system.
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";
// Allow the server to create a class loader to load service classes
permission java.lang.RuntimePermission "createClassLoader";
// Give the server permission to read the directory that contains the
// service classes. If we were using a network URL instead of a file URL,
// we'd need to add a SocketPermission instead of a FilePermission
permission java.io.FilePermission "${service.dir}/-", "read";
// The server cannot grant permissions to the Service classes unless it
// has those permissions itself. So we give the server these two Service
// permissions.
permission java.util.PropertyPermission "service.tmp", "read";
permission java.io.FilePermission "${service.tmp}/-", "read,write";
};
// Grant permissions to classes loaded from the directory
specified by the
// service.dir system property. If we were using a network
URL instead of a
// local file: URL, this line would have to be different.
grant codeBase "file:${service.dir}" {
// Services can read the system property "service.tmp"
permission java.util.PropertyPermission "service.tmp", "read";
// And they can read and write files in the directory specified by
// that system property
permission java.io.FilePermission "${service.tmp}/-", "read,write";
};


7.2.2 Testing SafeServer


To
demonstrate that SafeServer runs its services
safely, you need a demonstration service. Example 7-3 shows one such service that attempts various
restricted actions and reports its results. Note that since
you're going to load this class with a custom class
loader, rather than from the class path, I haven't
bothered to give it a package statement.

Example 7-3. SecureService.java

import je3.net.*;  // Note no package statement here.
import java.io.*;
/**
* This is a demonstration service. It attempts to do things that may
* or may not be allowed by the security policy and reports the
* results of its attempts to the client.
**/
public class SecureService implements Server.Service {
public void serve(InputStream i, OutputStream o) throws IOException {
PrintWriter out = new PrintWriter(o);
// Try to install our own security manager. If we can do this,
// we can defeat any access control.
out.println("Trying to create and install a security manager...");
try {
System.setSecurityManager(new SecurityManager( ));
out.println("Success!");
}
catch (Exception e) { out.println("Failed: " + e); }
// Try to make the Server and the Java VM exit.
// This is a denial of service attack, and it should not succeed!
out.println( );
out.println("Trying to exit...");
try { System.exit(-1); }
catch (Exception e) { out.println("Failed: " + e); }
// The default system policy allows this property to be read
out.println( );
out.println("Attempting to find java version...");
try { out.println(System.getProperty("java.version")); }
catch (Exception e) { out.println("Failed: " + e); }
// The default system policy does not allow this property to be read
out.println( );
out.println("Attempting to find home directory...");
try { out.println(System.getProperty("user.home")); }
catch (Exception e) { out.println("Failed: " + e); }
// Our custom policy explicitly allows this property to be read
out.println( );
out.println("Attempting to read service.tmp property...");
try {
String tmpdir = System.getProperty("service.tmp");
out.println(tmpdir);
File dir = new File(tmpdir);
File f = new File(dir, "testfile");
// Check whether we've been given permission to write files to
// the tmpdir directory
out.println( );
out.println("Attempting to write a file in " + tmpdir + "...");
try {
new FileOutputStream(f);
out.println("Opened file for writing: " + f);
}
catch (Exception e) { out.println("Failed: " + e); }
// Check whether we've been given permission to read files from
// the tmpdir directory
out.println( );
out.println("Attempting to read from " + tmpdir + "...");
try {
FileReader in = new FileReader(f);
out.println("Opened file for reading: " + f);
}
catch (Exception e) { out.println("Failed: " + e); }
}
catch (Exception e) { out.println("Failed: " + e); }
// Close the Service sockets
out.close( );
i.close( );
}
}

To test SafeServer with the
SecureService class, you have to decide which
directories you'll use for storing the service
classes and for the scratch directory. In the material that follows,
I've used /tmp/services and
/tmp/scratch as the directory names.

First, compile SecureService using the
-d option to tell javac where
to put the resulting class file:

% javac -d /tmp/services SecureService.java

It is important that you make sure there isn't a
copy of the SecureService.class file in the
current directory or anywhere else that Java might find it in the
local class path. If the URLClassLoader can find
the class locally, it won't bother loading it
through the URL you specify.

Now, to run the
SafeServer class, specify the name of the
SecureService class, the URL to load it from, the
port to listen for connections on, and four different system
properties with -D options:

% java -Djava.security.manager -Djava.security.
policy=SafeServer.policy -Dservice.dir=/tmp/services -Dservice.
tmp=/tmp/scratch je3.security.SafeServer
file:/tmp/services/ SecureService 4000

This is a complicated command line, but it produces the desired
results. When you connect to port 4000, you get the following output
from the service:

% java je3.net.GenericClient localhost 4000
Connected to localhost/127.0.0.1:4000
Trying to create and install a security manager...
Failed: java.security.AccessControlException: access denied
(java.lang.RuntimePermission createSecurityManager)
Trying to exit...
Failed: java.security.AccessControlException: access denied
(java.lang.RuntimePermission exitVM)
Attempting to find java version...
1.3.0
Attempting to find home directory...
Failed: java.security.AccessControlException: access denied
(java.util.PropertyPermission user.home read)
Attempting to read service.tmp property...
/tmp/scratch
Attempting to write a file in /tmp/scratch...
Opened file for writing: /tmp/scratch/testfile
Attempting to read from /tmp/scratch...
Opened file for reading: /tmp/scratch/testfile
Connection closed by server.


/ 285