SeMoA stands for "Secure Mobile Agents". It is about developing an
extensible and open server for mobile agents. The server is written in Java,
and agents can be written in Java as well (JavaSE).
The focus is on all aspects of mobile agent security, including protection of
mobile agents against malicious hosts.
Table of Contents
Introduction
Security Architecture
Agent Structure
Runtime Security
Limitations
Other Features
Introduction
Mobile agents push the flexibility of distributed systems to their limits
since not only computations are distributed dynamically, the code that
performs them is also distributed. Once let loose, mobile agents roam the
network, seek information, and carry out tasks on behalf of their senders
autonomously. Upon return to their senders the agents present the results of
their endeavors. Meanwhile the user is freed of the obligation to permanently
monitor the application's progress. This makes mobile agents particularly
useful in mobile environments (disconnected operation), because no permanent
network connection must be maintained in order to run the agent-based
application. Mobile agents also offer great benefits to applications in
"wired" networks by adding client-side intelligence and
functionality to server-side services unified under a homogenous access
paradigm. Furthermore, mobile agents offer considerable network bandwidth
savings because they can migrate to, and process data, at the source of that
data, which therefor need not be shipped back and forth across the network.
In order to exploit benefits such as the ones described
above, mobile agent frameworks have to cope with a number of security
threats. A mobile agent's itinerary in general spans a number of servers which
might be run by competing operators. Apart from monitoring, manipulating, and
stealing data from mobile agents, malicious hosts might try to abuse
passing agents as Trojan Horses in attacks on competing servers while
incriminating the agent's owner in the process. On the other hand, hosts have
to be aware of malicious agents breaking into the server in order to
harm other agents hosted by it, or to gain unauthorized system access. Mobile
agents make a perfect cover for viruses and Trojan Horses. In particular,
mobile agents might try to attack remote hosts using innocent hosts as launch
pads in order to cover the tracks of the attacker. Both agents and servers are
threatened by attacks originating from outside the system. Eavesdroppers might
snoop on agents being transfered over network connections hence compromising
the privacy of agents. They might also launch acive attacks on servers either
directly or indirectly by manipulating agents during transport. A sound
security model which is able to resist these attacks is fundamental to
business acceptance and market exploitation of this fascinating technogy.
SeMoA Security Architecture
SeMoA builds on JavaSE and is a ``best effort'' to provide adequate security
for mobile agent systems, servers as well as agents. The security architecture
of the SeMoA server compares to an onion: agents have to pass all of several
layers of protection before they are admitted to the runtime system (see
Figure 1 for illustration) and the first class of an agent is loaded into the
server's JVM.
The first (outer) security layer is a transport layer security
protocol such as TLS or SSL. At the time of writing, the SSL implementation is
used that comes with the JSSE framework provided by Sun Microsystems. This
layer provides mutual authentication of agent servers, transparent encryption
and integrity protection. Connection requests of authenticated peers can be
accepted or rejected as specified in a configurable policy.
The second layer consists of a pipeline of security filters. Separate
pipelines for incoming agents and outgoing agents are supported. Each filter
inspects and processes incoming/outgoing agents, and either accepts or rejects
them. We refer to this filtering procedure also as content inspection
in analogy to concepts known from firewalls. At the time of writing,
SeMoA features two complementary pairs of filters that handle digital
signatures and selective encryption of agents (signature verification and
decryption of incoming agents, encryption and signing of outgoing agents). An
additional filter at the end of the incoming pipeline assigns a configurable
set of permissions to incoming agents, based on information established and
verified by preceeding filters. Permissions can be granted based on the
authenticated identities of the agent's owner, the sponsor of its last state
change, and its most recent sender. Filters can be registered and unregistered
either dynamically or at boot time of the SeMoA server either
programatically or by means of script executed at boot time.
Subsequent to passing all security filters, SeMoA sets up a sandbox for the
accepted agent (which can be regarded as layer four). Each agent gets a
separate thread group and class loader. The agent is unmarshalled by a thread
that is already running within the agent's thread group and becomes the first
thread of that agent. Marshalling is done by the very same thread after all
remaining threads in the agent's thread group have terminated. Since the
Serialization Framework of Java provides callbacks that pass control back to
objects to be serialized, the thread once again blocks until no more threads
remain in the agent's thread group. Only then does SeMoA handle any
migration requests of that agent. This prevents agents from flooding a network
of agent servers by migrating and refusing to terminate at the same time.
An agent's classes are loaded by its dedicated class loader. This class loader
supports loading classes that came bundled with the agent, as well as loading
classes from remoted code sources specified in the agent. All loaded classes
(save those in the class path of the server) are verified against a
configurable set of trusted hash functions. The digests of verified classes
must match corresponding digests signed by the agent's owner (which can be
regarded as layer three). Thus, only classes authorized by the agent's owner
for use with his agent are loaded into the agent's namespace.
Agents cannot share classes so one agent cannot not load a Trojan Horse class
into the name space of any other agent. However, in order to allow method
invokations between agents, they may share interfaces. Interfaces are deemed
to be the same if their trusted digests match. In this case, an agent's class
loader returns a previously loaded interface rather than loading the interface
again from the served agent, so that the interfaces used by the agents are
type-compatible wherever possible. Of course, this works only if the interface
classes referenced by two agents are bitwise identical. Improved schemes may
compare interface implementations on the API level. However, this adds
overhead to the class loading process, and is not yet implemented. Interface
objects are managed in a Map that is global to all agent class
loaders. Pollution attacks on this Map require breaking all trusted
hash functions simultanously.
Before a class is defined in the Java VM, the bytecode of that class has to
pass a filter pipeline similar to the one for incoming agents. Each class
filter can inspect, reject, and even modify the bytecode. SeMoA comes with
an example filter that rejects classes which implement finalize().
Malicious agents may implement this method in order to attack the garbage
collector thread of the hosting VM. Additional filters may implement bytecode
arbitration e.g. in order to add resource accounting to agent classes.
Agents are separated from all other agents in the system; no references to
agent instances are published by default. The only means to share instances
between agents is to publish them in a global environment. Each agent
gets its own view on this environment (referred to as the agent's
environment), which tracks the objects registered by that agent. All
published objects are wrapped into proxys which are created dynamically. If
the agent terminates or retracts a published object, then the agent's
environment instructs the handler of the corresponding proxy to invalidate
its link to the original object. This makes the original object unavailable
even to other agents that looked up its reference in the global environment.
This also makes the original object available for garbage collection.
Agent Structure
In SeMoA, mobile agents are transported as Java Archives (JAR files). The JAR
specification of Sun Microsystems extends ZIP archives with support for
digital signatures by means of adding appropriate signature files to the
contents of the ZIP archive. The signature format is PKCS#7, a cryptographic
message syntax standard which builds on standards such as ASN.1, X.501, and
X.509. Using PKCS#7 as well, SeMoA extends the JAR format with support for
selective encryption of JAR contents with multiple recipients. Encryption and
decryption is handled transparently for agents by the filters described in the
previous section. In order to prevent encrypted parts of an agent from being
copied and used in conjunction with other agents (cut & paste
attacks), these filters implement a non-interactive proof of knowledge of the
required decryption keys.
Each agent bears two digital signatures. The entity that signs the
static part of an agent (the part that remains unchanged throughout
the agent's lifetime) is taken as the rightful owner of that agent
(the entity on whose behalf the agent is acting). Each sending server also
signs the complete agent (static part plus mutable part); therefor it
binds the new state of the agent to its static part. In other words, agent
servers commit to the state changes that occurred to an agent while they
hosted this agent.
Agents can use abstractions comparable to the combination of a Map
interface and a filesystem in order to access the data stored in their static
and mutable part (denoted its structure, see Figure 2). When an
agent migrates, its structure is processed by the outgoing security filters,
and is compressed back into a JAR for transport to its destination host. The
marshalled instance graph of an agent is also stored in the agent's
structure. As a side effect, agents can schedule the computation of snapshots
as they see fit. Agent structures can be backed both by persistent and
non-persistent storage, depending on the server's configuration. The agent
structure also contains properties of the agent (key/value pairs), such as a
human readable nickname of the agent and code sources to load classes
from. The properties must be signed by the agent's owner, thus they are
protected against tampering.
In addition, SeMoA computes implicit names from agents, by applying
the SHA1 digest algorithm to its owner's signature. This renders agent names
globally unique as well as anonymous. Implicit names are used in SeMoA to
provide agent tracing as well as scalable location-independent routing of
messages among agents.
Runtime Security
SeMoA uses the Java 2 security model in order to control access to critical
objects within the server. Permissions granted to agents are defined by the
policy filter on the incoming filter pipeline. These permissions are assigned
to all classes loaded into the name space of the agent (e.g. classes brought
by the agent or classes loaded from one of the codesources specified in this
agent's properties). SeMoA allows authorized code to revoke permissions of
agents at runtime. The consequences of the revocation are immediate and apply
to all classes of the agent's namespace. This allows to limit the impact of
agents that "run wild" in the server.
Limitations
We decided to build SeMoA on a regular Java Virtual Machine (VM) with
unmodified core packages. This rules out a number of protective measures that
are, in principle, expected from a viable and secure mobile agent platform.
The foremost shortcoming is the lack of proper resource control in the
Java VM. As a consequence, SeMoA is not robust against a number of DoS
(Denial-of-Service) attacks such as memory exhaustion.
Another problem is the forced termination of agents or -- more precisely --
the termination of threads. All methods that allow to stop threads are
deprecated in Java 2 and using them anyway provokes inconsistent object
states. Even if stop() is called on the thread of an agent then the
agent might still catch the resulting ThreadDeath (or any other
Throwable) that is propagated up the thread's stack and continue. For
the time being we chose to ignore this problem. The SeMoA server flags down
agents in case they should terminate, and builds on their cooperation.
Last not least there are a number of classes in the core package which
synchronize on the class object itself. Since local classes are shared and
their visibililty is global any agent that acquires a lock on such a class
object effectively blocks any other threads attempting to access them.
Some of these issues can be dealt with by means of dynamic byte code
rewriting, restrictions on the visibility of core classes, and minimization of
shared classes. We did not yet implement said protective mechanisms though the
architecture of SeMoA supports easy integration of filters suitable for this
purpose.
In summary, a number of shortcomings of Java can be used by malicious agents
to launch various DoS attacks. However, in order to do so, agents need to run
first. But before an agent is run (and even before classes of the agent are
loaded), SeMoA servers verify the claimed identity of the agent's owner
based on digital signatures and certificates. Though the culprit can try to
cover his tracks, there is a chance that he can be tracked by means of
evidence logged to a secure host.
Other Features
SeMoA comes with classes that enable transparent per-thread
redirection of standard input, output, and error channels. Though not
explicitly supported, yet, it is in principle possible to re-route error
output from one agent (or more precisely: from its threads) across the network
to a debug monitor where this output then appears. This is an interesting
feature to debug agents under development. All that agents have to do, is to
write error output to System.err. For operational agents, the error
stream can be redirected to a log file in the agent's structure which is
brought back to the agent's owner upon the agent's return. The log file can
then be inspected or forwarded to the programmer of the agent's code.
One of the most striking features of the SeMoA architecture
is its openess, both in terms of adding new features and supporting
interoperability among different agent systems. Agents are not managed by the
server directly but by using an abstraction called Lifecycle. A
Lifecycle is the system's view on the agent, wraps around a matching
agent, provides a familiar view of the system to the agent, and translates
between the native SeMoA view and the one expected by the agent. Different
Lifecycle factories can be registered in the SeMoA server, thus
multiple agent systems can be emulated in parallel, potentially allowing
heterogenous agent types to interoperate. However, the quality of the
emulation depends on the quality of the design of the emulated system. The
clearer and the more concise the interfaces of a system are, the easier can it
be integrated and emulated. As a consequence, no special class must be
subclasses by agents in order to run in the SeMoA server. The server comes
with a default Lifecycle which supports the Runnable interface,
the simplest form of starting Java code that is possible. Future extensions
may include convenience classes that make certain features of the server
available to agents by means of an abstract agent class. However, implementing
these is by no means a requirement for agents to run in the server. We already
demonstrated the integration of JADE agents in SeMoA, and are working on
Aglets at the time of writing.
Most of the components in SeMoA are easily replaceable by custom
implementations, in many cases simply by implementing the appropriate
interface. A central object registry (the global environment) is used
to locate e.g. filters and services that make up the server by means of a
well-known name. These names are structured hierarchically, comparable to a
filesystem. Access to the environment is controlled by means of the Java 2
security mechanisms. A shell allows quick and easy browsing and
manipulation and of this registry either by command line tools or by shell
scripts (including variable substitutions, aliases, pipes and more features
expected from a shell). A graphical (e.g. Swing-based) front end to the
registry does not yet exist, but is straightfoward to implement.
|