[SeMoA Logo Strip] [SeMoA Logo Strip] [SeMoA Logo Strip]
 About  -  Documentation  -  Download  -  Misc 

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

  1. Introduction

  2. Security Architecture

  3. Agent Structure

  4. Runtime Security

  5. Limitations

  6. 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.