This is an discussion for developers and interested bystanders of implementing zones and security in Apache JServ. It describes the point of the feature, different implementation alternatives, and current problems. Please send comments to the mailing lists.
Each `servlet mount point' in the web server specifies the name of a servlet zone for that virtual directory. Servlet zones partition up the Apache JServ virtual machine into secured, separated spaces for different applications or users. It will be impossible for code inside one zone to see or interact with code in another zone; and for code inside a zone to interact with the Java server implementation except through defined interfaces. Zones can be thought of as solipsistic little JServ engines, but without the overhead of running a separate JVM for each zone. This will allow multiple users to work on a single web server without needing to run multiple VMs; and for people to use untrusted servlet code safely. This proposal assumes a socket-based connection vaguely similar to that of AJPv1.1 and our current consensus on AJPv2.1. Interested people are referred to the Java Language Specification for more details and legalese.
The web server module will pass the name of the zone in each request.
The Apache JServ configuration files contain default properties and per-zone properties.
Per-zone properties include: A security ACL, specifying operations that are allowed and disallowed A list of repositories (directories, ZIPs, and JARs) to be searched for classes. Whether autoreloading of changed classes should happen or not. Servlet aliases, mapping short names (jobservlet) into fully-qualified class names (org.apache.java.JobServlet). A list of servlets to be loaded at start-up, and initialization arguments. Pool management settings. [others?]
Global properties include The authentication string. Tracing options [others?]
Classes may be loaded into a Java virtual machine either using the default classloader provided by the VM, or using a custom classloader implementation. When ClassLoaders are in play, there may be several classes in the JVM with the same canonical name. The JVM looks up classes using a dictionary keyed by class name and classloader.
A JVM initially has no SecurityManager installed. Once a SecurityManager has been installed, it is illegal to try to install (or even construct) a new one.
JServ will install a JServSecurityManager object at startup: this object allows full privileges to JServ code and restricts user code depending on the zone from which it is loaded.
Operations subject to SecurityManager control include: System.exit() Linking native libraries Executing external programs Reading/writing/deleting files/directories Listening/connecting to TCP ports Creating/stopping/suspending threads
Servlet zones are represented by a JServZone object. This class will be similar to JServServletManager in 0.9. When JServ receives a request from the server, it will look up the name and route it to the appropriate zone for handling.
Each zone uses a single JServClassLoader at any time. This classloader loads classes from the repositories specified for that zone. The classloader has the option of requiring that certain classes be loaded from the system, rather than from user directories. The JServClassLoader will refuse to load classes in java.*, javax.*, or org.apache.jserv.* from within the zone repositories. (Allowing users to install classes into these packages might give them access to security-critical default-access members.)
JServ 0.9.7 already uses ClassLoaders in a similar fashion to reload changed classes.
System classes are taken from the classpath specified when the JVM is started. Generally, this path should only include java.*, javax.*, and org.apache.*, but other classes that definitely will not change and which can be shared across all zones (perhaps for example database drivers) may be included.
The Java VM will not permit a ClassLoader to redefine a class once it has supplied a definition. However, it will permit us to request that a class of the same name be loaded from a different classloader, as from Java's point of view this is a different Class. Therefore, when a JServZone detects that a repository element has been changed, it discards the classloader, creates a new one, and reloads the class.
If an operation is disallowed, generally it throws a SecurityException (extends RuntimeException) which if uncaught will terminate the servlet. If an operation is allowed, it completes normally.
Optionally, we should log all attempted security violations, even if they are caught by client code.
When the SecurityManager is called, it has to determine which zone the call comes from.
One possible implementation is to run each zone within a separate ThreadGroup, and have the SecurityManager check which ThreadGroup called it.
All operations within a particular zone take place within a particular ThreadGroup. Classes in that zone can create new Threads, and new ThreadGroups as children of their group, but may not create threads within other ThreadGroups, or stop or signal threads in other zones.
This could be implemented by creating a new thread within the appropriate ThreadGroup on each request, similar to the way new threads are created to handle each request in 0.9.7. Better, since WorkerPool extends ThreadGroup it should be possible to use Worker Pools and gain their performance advantage.
When the JServSecurityManager is asked to check an operation, it identifies the ThreadGroup from which the operation was called, and finds the JServZone which owns that ThreadGroup. If the ThreadGroup was not directly created by a Zone, then the JServSecurityManager checks its parents recursively to see if any of them execute within a zone.
If none of the ThreadGroups belong to a zone, then the operation is being attempted from system code or JServ itself and generally should be allowed.
JDK1.2b4 includes a very flexible standard means of specifying policy based on code location and signatures. It makes an Apache JServ specific implementation fairly redundant.
Some changes may be necessary in the ClassLoader implementation in JDK1.2 to do secure ClassLoaders.
Sessions are private to each zone: the session cookie ID will include the zone name, so that more than one zone can have sessions open on a particular browser at the same time. Other zones will be able to see the cookie IDs, of course, by examining the headers, but they will not have access to the server-side objects it points to.
There's a possible attack in which a hostile servlet connects back to the web server's http port and pretends to be a client presenting the cookie it just sniffed. An administrator should take advantage of the security manager's ability to limit outgoing sockets to turn this off it they expect malicious and sophisticated code.
Conflicting SecurityManagers
A JVM may only have a single SecurityManager loaded at any time, and once installed it may not be replaced.
Some other applications require SecurityManagers to be loaded, and they _may_ not be able to execute within a JServ VM. (RMI, for example, should be compatible as it only requires a security manager but does not care what class it is.) I would be interested to hear from people who think this might be a problem.
Backward compatibility
The default settings for security are a bit of a conundrum: for compatibility with 0.9.7, we ought to ship with everything allowed so as not to break existing code; but shipping with all the doors unlocked earns one a bad reputation.
Copyright (c) 1997-98 The
Java Apache Project.
$Id: sandboxing.html,v 1.3 1999/06/09 05:21:26 jonbolt Exp $
All rights reserved.