Realisierung von Teilen eines Systems für den Zugriff auf multimediale Datenbanken mittels wandernder Agenten in einem Intranet. Diplomarbeit von cand. Dipl. Ing. Kerstin Aßmus Betreuer: Dipl. Ing. Mehrdad Jalali IGD A8, Sicherheitstechnologien für graphische und Kommunikationssysteme Prof. José Luis Encarnação TU Darmstadt, Fachbereich Informatik, Graphisch-Interaktive Systeme Prof. Dr.-Ing. Ralf Steinmetz Betreuer: Dipl. Wi-Inf. Martin Karsten TU Darmstadt, KOM - Industrielle Prozeß- und Systemkommunikation Erklärung Hiermit erkläre ich an Eides statt, die vorliegende Arbeit selbständig und nur mit den angegebenen Hilfsmitteln angefertigt zu haben. Darmstadt, den 18. August 1997 ( Kerstin Aßmus ) Inhaltsverzeichnis 1. Einleitung.......................................................................................................................... 1 2. Grundlagen........................................................................................................................ 3 2.1 Internet, Intranet und Protokolle ......................................................................... 3 2.2 Datenbank............................................................................................................ 6 2.2.1 Relationale Datenbanken...................................................................... 6 2.2.1.1 Grundlagen des relationalen Systems.................................... 7 2.2.2 Microsoft Access Datenbank.............................................................. 12 2.3 Java™ ................................................................................................................ 13 2.3.1 Java JDBC™....................................................................................... 15 2.3.1.1 JDBC/ODBC Bridge ........................................................... 16 2.3.2 Java Remote Method Invokation........................................................ 18 2.3.2.1 RMI Interfaces und Klassen ................................................ 19 2.3.2.2 RMI Systemarchitektur ....................................................... 21 2.3.2.3 RMI Sicherheitsmechanismen............................................. 22 2.3.3 Java Security...................................................................................... 27 2.3.3.1 Java.security.acl Package .................................................... 28 2.3.3.2 Javakey ................................................................................ 30 3. Agenten............................................................................................................................ 34 3.1 Formale Definition eines Agenten..................................................................... 34 3.2 Mobile Agenten ................................................................................................. 35 3.3 Agentensprachen ............................................................................................... 39 3.3.1 Kommunikationssprachen ........................................................................ 39 3.3.2 Programmiersprachen......................................................................... 40 3.3.3 Der Datenbankzugriff durch einen Agenten....................................... 41 3.4.1 Architektur.......................................................................................... 42 3.4.2 Verwendete Sicherheitsmechanismen ................................................ 44 3.4.3 Der Server AgServer .......................................................................... 46 3.4.4 Der Client RemoteClient .................................................................... 47 3.4.5 Das Interface AgInterface................................................................... 49 3.4.6 Das remote Objekt AgObjekt ............................................................. 50 3.4.7 Die Verbindung zu den Datenbanken „FhG“ und „ThD“ .................. 50 3.5 Andere Projekte über Mobile Agenten.............................................................. 52 4. Ausblick........................................................................................................................... 55 5. Literaturverzeichnis......................................................................................................... 57 Bildverzeichnis Bild 2.1.1 Bild 2.1.2 Bild 2.2.1 Bild 2.2.2 Bild 2.2.3 Bild 2.3.1 Bild 2.3.1.1.a Bild 2.3.1.1b Bild 2.3.1.1.2 Bild 2.3.2.1 Bild 2.3.2.2 Bild 2.3.2.3 Bild 2.3.2.4 TCP/IP-Protokollfamilie.......................................................................... 3 Internetstruktur ........................................................................................ 5 Die 1. Normalform .................................................................................. 8 Die 2. Normalform .................................................................................. 9 Die 3. Normalform ................................................................................ 10 Die verschiedenen Schritte bei der Ausführung von Javaprogrammen 14 Two-tier Modell..................................................................................... 16 Three-tier Modell................................................................................... 16 JDBC/ODBC Bridge ............................................................................. 17 Remote Procedure Call (RPC)............................................................... 18 Zusammenhang zwischen RMI Interfaces und Klassen........................ 20 Architektur des RMI Systems ............................................................... 21 Serialisation und Deserialisation ........................................................... 25 Bild 3.1.1 Bild 3.1.2 Bild 3.4.1.1 Bild 3.4.1.2 Bild 3.4.1.3 Bild 3.4.3.1 Bild 3.4.3.2 Agentenklassifikation ............................................................................ 36 Agentenwelt........................................................................................... 37 Systemarchitektur .................................................................................. 42 Programmarchitektur ............................................................................. 42 Architektur des Datenbankzugriffs durch RMI ..................................... 43 Objektregistrierung und -aufruf............................................................. 48 Parameterserialisierung Bild 4.1 Geplante Architektur des Agentensystems............................................ 56 Tabellenverzeichnis Tabelle 2.2.1 Tabelle 2.2.2 Tabelle 2.3.3.1 Tabelle 2.3.2.1 Tabelle 2.3.3.1 Tabelle 2.3.3.2 Die wichtigsten Normalformen und ihre Regeln.................................. 7/8 Verknüpfungstypen ............................................................................... 11 Java JDBC Lösungen ............................................................................ 15 6 Grunde für den Einsatz von Java RMI ............................................... 19 Kalkulation der Berechtigungen............................................................ 29 Vorzüge eines JAR-Files.................................................................. 31/32 Tabelle 3.1.1 Agentenmerkmale............................................................................. 34/35 Tabelle 3.4.1 Sicherheitsaspekte des RMISecurityManagers ................................ 44-46 1. Einleitung Das World Wide Web ist auf dem Weg zu einer der wichtigsten Umgebungen für kommerzielle Dienstleistungen zu werden. Ein wichtiger Aspekt für den Erfolg solcher Dienste ist die gewährleistete Sicherheit für alle beteiligten Parteien. Sicherheitsrisiken, die verhindert werden sollen, sind: • • • • Das Lesen von vertraulichen Dokumenten Die Abhörung sensitiver Daten wie Geheimnummern etc. Veränderung von Daten während der Kommunikation Vortäuschen falscher Identitäten. Ein sicherer mobiler Agent, der über das Netz läuft und Datenbanken kontaktiert, sollte also folgenden Anforderungen genügen: Authentifikation der Kommunikationspartner, Vertraulichkeit von Daten durch z. B. Verschlüsselungen zu gewährleisten, Verbindlichkeit von z. B. Verträgen durch digitale Signaturen unterstützen und Integrität der Daten durch z. B. digitale Fingerprints zu überprüfen. In Kapitel 2 werden die Grundlagen besprochen, die bei der Konzeption und Implementierung des Agenten für den Zugriff auf die Datenbank verwendet werden. Auch die Sicherheitsmechanismen, die bei einem erweiterten Modell implementiert werden können, werden diskutiert. Im ersten Abschnitt von Kapitel 2 werden die Protokolle, die bei einer Kommunikation über das Inter- oder Intranet verwendet werden, und die Netzstruktur der erwähnten Netze erläutert. Der zweite Teil befaßt sich mit relationalen Datenbanken. Für die Konzeption einer solchen Datenbank gibt es bestimmte Regeln, um redundante Informationen und damit Fehler in der Verwaltung der Daten zu vermeiden. In der vorliegenden Arbeit wird die relationale Datenbank Ms Access von Microsoft verwendet. Das Grundlagenkapitel schließt mit der Diskussion über Java und den für diese Arbeit relevanten Teilgebieten von Java wie Java JDBC (Java DataBase Connectivity), Java RMI (Remote Method Invokation) und Java Security. JDBC ist eine API zum Ausführen von SQL Statements zur Arbeit mit relationalen Datenbanken. Damit ist ein datenbankunabhängiger Zugriff auf Datenbanksysteme möglich. Die Anbindung an die Datenbank erfolgt durch die Jdbc-Odbc-Bridge. Java RMI wird benutzt, um einen entfernten Aufruf von Serverobjekten und Methoden zu realisieren. RMI erweitert und vereinfacht die Anwendung von Java Sockets, die grundsätzlich zur Kommunikation in verteilten Systemen angewandt wird. Grundlage von RMI sind Prozedurenfernaufrufe (RPC). Schließlich wird Java Security diskutiert. Damit sind Sicherheitsmechanismen gegeben, die alle Aktionen der Kommunikation über das Netz betreffen. Es bleibt abzuwarten, wie sich dieses Paket entwickelt und welche Möglichkeiten hinzukommen, um alle möglichen Sicherheitslücken zu schließen. Kapitel 4 widmet sich den Agenten. Der erste Teil behandelt Agenten allgemein, die Definition, ihre Kennzeichen und mögliche Sicherheitsrisiken. Im zweiten Teil wird das in dieser Arbeit entwickelte und implementierte System vorgestellt. Es basiert auf einer RMI und Client/Server Architektur. Daran schließt sich die Vorstellung anderer Projekte zum Thema mobile Agenten. Im Ausblick wird aufgezeigt, welche Schritte als nächstes folgen könnten, um das Ziel eines sicheren mobilen Agenten zu erreichen. 2. Grundlagen 2.1 Internet, Intranet und Protokolle In diesem Kapitel wird ein Einblick über die Protokolle gegeben, die bei der Kommunikation über das Inter- oder Intranet verwendet werden. Informationen müssen immer schneller verfügbar sein und der Datenzugriff soll möglichst einfach bleiben, d. h. unabhängig von z. B. Datenbanken und Plattformen sein. Damit wird gewährleistet, daß Softwareentwickler nicht an bestimmte Hersteller gebunden sind, sondern auf Änderungen schnell reagieren können. Sinnvoll sind daher Lösungen mit Zugriff auf die gewünschten Daten innerhalb von Internet/Intranet-Strukturen, um Änderungen innerhalb der Netze global ausführen zu können. Das Intranet ist ein internes, nichtöffentliches Netz z. B. innerhalb einer Firma, das Internet ist der öffentliche Zusammenschluß von vielen Netzen, ohne Zugangsbeschränkung. Die Architektur des Internets ist so strukturiert, daß viele lokale Rechensysteme und kleinere Netze (auch Intranets) miteinander kommunizieren. Dazu werden standardisierte Protokolle verwendet. Trivial File Transfer Protocol TFTP Simple Network Management Protocol SNMP NFS XDR RPC User Datagram Protocol UDP File Transfer Protocol FTP Simple Mail Transfer Protocol SMTP X-Windows Transmission Protocol TCP Internet Protocol IP Internet Message Control Protocol ICMP Gateway-to-Gateway Protocols EGP, IGP, RIP, OSPF Keine speziellen Protokolle. Im LAN-Bereich meist Ethernet Bild 2.1.1 Telnet Protocol TELNET Ebene 5-7 Ebene 4 Ebene 3 Ebene 1-2 TCP/IP-Protokollfamilie Das wichtigste Protokoll ist das weit verbreitete TCP/IP (Transmission Control Protocol / Internet Protocol). Es steht für eine fehlergesicherte Punkt-zu-Punkt Verbindung zwischen zwei Rechnern im Netz. Durch IP-Nummern kann jeder Rechner eindeutig identifiziert werden. Das TCP garantiert außerdem einen Full-Duplex-Betrieb, d. h. Daten können in beide Richtungen gleichzeitig transferiert werden. Es kommt z. B. bei WWW (World Wide Web)-Servern zum Einsatz und liegt auch dieser Arbeit zugrunde. Das Versenden der vom Client geforderten Daten (Text, Sound, Bilder) im WWW geschieht durch das HTTP (HyperText Transfer Protocol). Ein anderes wichtiges Protokoll ist das UDP (User Datagram Protocol), das eingesetzt wird, wenn fehlerhaft übertragene Daten ignoriert werden können. Der Vorteil ist eine geringere Größe der Datenmenge, die sich aus dem Fehlen einer Fehlerkorrektur ergibt. Das wiederum ist kann aber ein Nachteil sein. Ein Beispiel dafür ist ein Börsenkursserver. Die Daten werden in bestimmten Zeitabständen neu übertragen, so daß ein paar falsch übertragene Daten zwischendurch nicht ins Gewicht fallen. Das Java Package java.net enthält alle Klassen für die Kommunikation über das Netz und die Arbeit mit Datagrammen, Sockets, IP Adressen und URLs bereit. Ein wichtiges Protokoll für eine gesicherte Datenübertragung ist SSL (Secure Socket Layer). Es wurde von Netscape Inc. und Paul Kocher entwickelt. SSL ist in die Netscape Produkte Suite integriert. Das Ziel von SSL ist die sichere Kommunikation über das Internet und die Befähigung von Client-ServerApplikationen, ihre Daten zu schützen. Schwerpunkte dabei sind Sicherheit durch Verschlüsselung, Erweiterbarkeit für neue Methoden, Effizienz durch Minimierung der nötigen Netzverbindungen und die Möglichkeit, daß Applikationen entwickelt werden können, die kryptografische Parameter austauschen, ohne den Code der anderen Seite zu kennen. SSL beinhaltet zwei Protokollschichten, den record layer für die Kompression, Fragmentierung und Verschlüsselung von Daten und das handshake protocol zur Stabilisierung der Sitzung und Datenübertragung. Wichtige Eigenschaften von SSL sind • Symmetrische Datenverschlüsselung. Die Verschlüsselung geschieht nach einem handshake zur Definition eines secrets keys • die Identität des Peer kann durch das public key Verfahren oder asymmetrische Kryptographie authentiziert werden • die Verbindung ist zuverlässig. Der Datentransport beinhaltet einen message integrity check, wobei Schlüssel für den Code zur Datenauthentizierung verwendet werden. Intranet Internet Intranet Bild 2.1.2 Internetstruktur 2.2 Datenbank Dieser Abschnitt behandelt die Grundlagen der relationalen Datenbank MsAccess, die in der vorliegenden Arbeit verwendet wird. Eine Datenbank (DB) ist eine Zusammenstellung von Daten, die einen komplexen Gegenstand oder Themenbereich beschreiben und zu diesem Zweck miteinander in Beziehung stehen [BLAS96]. Das Datenbankmanagementsystem (DBMS) verwaltet diese Daten in der Datenbank, d. h. es speichert sie oder ruft sie wieder ab. Am gebräuchlichsten sind zwei Arten von Datenbanken, die objektorientierte und die relationale. Da es in Java das Standardpackage java.sql für SQL-Anweisungen gibt und man damit auf die relationale DB zugreifen kann, wurde in dieser Arbeit das relationale Datenbankmanagementsystem Access von Microsoft® eingesetzt. 2.2.1 Relationale Datenbanken Ein relationales Datenbankmanagementsystem (RDBMS) ist Software wie z. B. Microsoft Access, die das Organisieren und Analysieren von Daten ermöglicht, die in Tabellen innerhalb einer Datenbank gespeichert sind [ACCESS93]. In einer relationalen Datenbank (RDB) können die Daten nach Gebieten geordnet werden. Die RDB besteht aus verschiedenen Objekten wie z. B. Formularen, Berichten, Tabellen usw. Berichte und Formulare können für sich alleine stehen, sie sind reine Anweisungen für die Datenausgabe. Tabellen sind komplizierter, da sie die zu verwaltenden Informationen enthalten. Im relationalen Datenbankmanagementsystem (RDBMS) stehen die Tabellen in Relation zueinander. Diese Beziehung regelt die Verknüpfung der Informationen aus den einzelnen Tabellen. Das relationale Modell nach E. F. Codd wurde erstmals 1970 formuliert, als Basis dient die mathematische Relationentheorie [BEPS97]. Im folgenden Abschnitt werden die Grundlagen eines relationalen Systems theoretisch als auch anhand eines fiktiven Beispiels erklärt. 2.2.1.1 Grundlagen des relationalen Systems Relationen Dieses Modell nutzt den Vorteil von Relationen, sich in Tabellen darstellen zu lassen. Deshalb wird in Access nur auf der Grundlage von Tabellen gearbeitet. Wichtig ist die Unterscheidung aller Datensätze in einer Relation oder auch Tabelle. Dazu werden Primärschlüssel eingesetzt, die entweder ein Attribut, ein sogenanntes Feld, sein oder sich aus der Kombination mehrerer Attribute ergeben können. In Microsoft Access wird eine Attributskombination zur Bildung einer identifizierenden Eigenschaft oder Eindeutigkeit nicht verwendet. Man bildet ein künstliches Attribut, d. h. ein Attribut, das den Mengen von Attributen, die Datensätze bilden, nicht logisch zugeordnet ist. Normalisierung Beim relationalen Modell unterscheidet man 5 Normalformen (von 1-5 durchnumeriert) und zusätzlich die Boyce-Codd-Normalform, die im Bereich der vierten und fünften Normalform anzusiedeln ist. Wichtig und am häufigsten umgesetzt werden jedoch nur die erste bis dritte Normalform. In den einzelnen Schritten der Normalisierung wird der gesamte Datensatz in einzelne Tabellen aufgespalten. Ziel dabei ist, redundante, also doppelte Informationen zu vermeiden, Platz zu sparen, Anomalien zu verhindern und die Zugriffsgeschwindigkeit auf die einzelnen Informationen zu steigern. Wichtig ist aber, daß alle ursprünglichen Informationen erhalten bleiben und keine falschen oder neuen hinzukommen. NORMALFORM REGEL 1. Normalform Eindeutigkeit der Attribute 2. Normalform Abhängigkeit vom Schlüssel 3. Normalform Keine transitive Abhängigkeit vom Primärschlüssel Tabelle 2.2.1 Die wichtigsten Normalformen und ihre Regeln Die Inhalte der Normalformen werden anhand einer Datenbank über Mitarbeiter einer beliebigen Abteilung erläutert. In der ersten Normalform wird gefordert, daß alle Elemente des Datensatzes, also alle Felder bzw. Attribute eindeutig sein müssen und daß keine zusammengesetzten Attribute mehr vorhanden sind., d. h. daß z. B. das Attribut Adresse in die Bestandteile Straße, Postleitzahl und Ort unterteilt wird. Bild 2.2.1 Die 1. Normalform Die zweite Normalform besagt, daß alle Attribute voll vom jeweiligen Primärschlüssel abhängen. Wird der Primärschlüssel durch ein künstliches Attribut gebildet, ergibt sich die Abhängigkeit der Attribute aus der Relation, d. h. alle Informationen müssen zueinander und zur Bezeichnung der Tabelle in einem logischen Zusammenhang stehen. Das bedeutet, daß die Elemente Straße und Ort eindeutig in die Tabelle Adresse gehören. Andere Daten, z. B. über laufende Projekte, gehören dagegen in eine eigene Tabelle Projekte. Mit der dritten Normalform soll erreicht werden, daß keine Redundanzen, d. h. doppeltes Vorkommen von Informationen, entstehen. So kann jeder Mitarbeiter an mehreren Projekten arbeiten, in der Projekttabelle wären damit redundante Informationen über die Projektmitarbeiter enthalten. Dem kann man vorbeugen, indem man eine Mitarbeiterstammtabelle anlegt, in der jedem Mitarbeiter eine persönliche Identifizierungsnummer ID zugeordnet wird, die dann statt Namen und Status in der Projekttabelle verwendet wird. In Access werden dauerhafte Verknüpfungen auf Systemebene definiert anstatt in Abfragen, Berichten oder Formularen festgelegt zu werden. Damit wird der referentiellen Integrität vorgebeugt. Bild 2.2.2 Die 2. Normalform Bild 2.2.3 Die 3. Normalform Referentielle Integrität Hierbei sind die Daten in Bezug auf ihre Verknüpfungen konsistent. Ist die referentielle Integrität verletzt, sind Daten in einer Tabelle vorhanden, aber es können die Verknüpfungen mit einer anderen Tabellen nicht ausgeführt werden, da die entsprechenden Verknüpfungen fehlen oder fehlerhaft sind. Dies kann z. B. durch unvollständiges Löschen von Daten innerhalb eines Datensatzes geschehen. Das DBMS ist verantwortlich dafür, daß die Integrität durch Sicherheitsmechanismen gewahrt bleibt. Anomalien Anomalien können durch falsch angelegte Daten- oder Tabellenstrukturen entstehen. Man unterscheidet drei Fälle von Anomalien: • die Insert-Anomalie, entsteht beim falschen Einfügen von Daten • die Update-Anomalie, entsteht beim falschen Ändern von bestehenden Daten • die Delete-Anomalie, entsteht beim falschen Löschen von bestehenden Daten. Verknüpfungen auf der Systemebene Bei der Tabellenverknüpfung definiert man eine Mastertabelle und die damit verbundenen Detailtabellen. Man unterscheidet vier Verknüpfungstypen: 1:1 Mastertabelle Detailtabelle Mastertabelle Detailtabelle Mastertabelle Detailtabelle Mastertabelle Detailtabelle 1:n n:1 n:m Tabelle 2.2.2 Verknüpfungstypen 2.2.2 Microsoft Access Datenbank Microsoft Access ist ein relationales Datenbankmanagementsystem für Microsoft Windows™. Ein großer Vorteil ist die Bedienoberfläche im "Microsoft Office-Look", mit der sich auch komplexe Aufgaben einfach lösen lassen. Im Netzwerk verwaltet ein automatischer Sperrmechanismus die Zugriffskonflikte, wenn mehrere Access Benutzer denselben Datensatz ändern wollen, indem während der Bearbeitung Speicherseiten von je 2048 Byte gesperrt werden. Dies hat zur Folge, daß auch benachbarte Datensätze unnötigerweise nicht zugänglich sind. Durch die Verwendung von ODBC zur Kommunikation stellt Access ein Frontend in Client/ServerUmgebungen dar. 2.3 Java™ Java ist eine streng objektorientierte Sprache, die es ermöglicht, mobilen Code zu erstellen und mit Hilfe der virtuellen Maschine (VM) in verteilten Anwendungen auszuführen. Damit lassen sich plattformunabhängige Anwendungen entwickeln, die auf beliebigen Rechnern laufen. Durch den verbreiteten Einsatz im Internet ist Java auf dem Weg, eine Standardsprache zu werden. Entwicklungsgeschichte von Java Java wurde ab 1990 bei Sun Microsystems™ entwickelt. Das Ziel war, mit dieser Sprache die Elektronik von Haushaltsgeräten zu steuern. Mit der Einführung des Netscape Navigators™ 2.0, eines Browsers mit der Fähigkeit Java-Programme auszuführen, wurde Java 1995 interessant für die Masse der Internet-Benutzer. Das war der Durchbruch. Viele Fähigkeiten und der größte Teil der Syntax von Java wurde von C++ übernommen. Im Gegensatz zu C/C++ liegt der Schwerpunkt der Programmierung in Java nicht bei der extremen Leistungsfähigkeit, sondern bei der Zuverlässigkeit und Fehlerfreiheit der Programme. Funktionsweise von Java Java ist eine Interpretersprache, d. h. das geladene Programm ist nicht selbst lauffähig, sondern muß von einem speziellen Programm interpretiert werden. Ein Java-Programm kann entweder als Applet oder als Applikation angelegt werden. Eine Applikation ist ein "standalone" Programm, d. h. es ist eine eigenständige Anwendung. Ein Applet dagegen wird in einen Browser geladen und dort innerhalb von Web-Seiten ausgeführt. Zur Ausführung eines Javaprogramms sind folgende Schritte nötig (siehe Bild 2.3.1): 1. Programmcode schreiben 2. zugehörige Klasse durch Compilierung erzeugen 3. Interpretieren des Byte Codes 4. Ausführen Java Editor .java Compiler z.B. Javac .class Applikation Interpreter z. B. Appletviewer, Netscape Navigator, Applet Hotjava 1. 2. 3. 4. Bild 2.3.1 Die verschiedenen Schritte bei der Ausführung von Javaprogrammen (aus [ERRE97]) Wird das Programm z. B. durch Javac compiliert, wird eine Klasse erzeugt, die den Byte Code enthält. Dieser kann nur von der Java Virtual Machine (JVM) ausgeführt werden. Der Vorteil liegt hier in der Kompaktheit (verringerte Ladezeit) des Codes und seiner Plattformunabhängigkeit, da er nicht für eine bestimmte Plattform erstellt wurde. Die JVM ist außerdem in der Lage, schon bei der Interpretation des Byte Codes zu Überprüfen, ob das Programm verbotene Zugriffe ausführen will. Ist dies der Fall, wird es nicht ausgeführt. Das ist eine wichtige Eigenschaft, gerade wenn man nicht weiß, welche Funktion Programme haben, die z. B. aus dem Internet geladen wurde. Mit Java wird häufig die Einbindung von Applets auf Web-Seiten assoziiert, das eigentliche Potential liegt jedoch in der Entwicklung von Client/Server-Anwendungen. Dabei spielt JDBC und damit die Anbindung an Datenbanken eine große Rolle. 2.3.1 Java JDBC™ Die am häufigsten genutzte Datenbankschnittstelle ist ODBC (Open DataBase Connectivity). Damit ist ein von der Datenbank unabhängiger Zugriff auf die Daten möglich. ODBC ist jedoch ein reines C-Interface, ist also für eine Java-Anwendung nur bedingt geeignet, da C-Aufrufe in Java-Applikationen bezüglich Sicherheit, Portabilität und Implementierung problematisch sind. [INTER97]. Darum hat JavaSoft in Zusammenarbeit mit Intersolv eine API entwickelt, die die Lücke zwischen ODBC und Java schließt: JDBC (Java DataBase Connectivity). JDBC bietet ein generisches SQL-Datenbank-Interface und eine Java API zum Ausführen von SQL-Anweisungen. Damit wird eine Standard API zur Verfügung gestellt, die es erlaubt, Datenbankapplikationen zu schaffen, die nur in Java geschrieben sind und damit datenbankunabhängig werden. JDBC basiert auf dem X/Open-SQL-Call-Level-Interface, welches auch die Grundlage von ODBC ist [JDBC97]. Es gibt vier Möglichkeiten, Java Anwendungen durch JDBC mit Datenbanken zu verbinden: ODBC/JDBC Bridge Native API Partly-Java Drivers Net-Protocol All-Java Drivers Native-Protocol All-Java Drivers Tabelle 2.3.1.1 Übersetzung von JDBC-Aufrufen in ODBCAufrufe JDBC-Aufrufe werden in die spezifische API der DB übersetzt, eine Java Bridge DLL sichert den Zugang zu C/C++-Software zum Netzwerktransport JDBC-Aufrufe werden über DBMSunabhängige Netzwerkprotokolle in ein DBMS-Protokoll übersetzt, ein Java-Treiber für viele DBMS Übersetzung der JDBC-Aufrufe in das zum DBMS gehörige Netzwerkprotokoll, direkter Zugang vom Client zur DB Java JDBC Lösungen In der JDBC Spezifikation wird empfohlen, einen Treiber zu verwenden, der das "ANSI SQL-92 Entry Level" unterstützt. So wird erreicht, daß die ganze Bandbreite der Möglichkeiten von JDBC ausgenutzt werden kann [BEPS97]. 2.3.1.1 JDBC/ODBC Bridge Die JDBC API unterstützt zwei Modelle des Datenbankzugriffs, das 'Two-tier und das Three-tier Modell. Im Two-tier-Modell kommuniziert das Java Applet oder die Applikation direkt mit der Datenbank in einer Client/Server-Architektur (Bild 2.3.1.1.1a). In einem Three-tier-Modell werden die Anfragen an die mittlere Ebene gerichtet, diese handhabt dann die Weiterleitung der SQL-Statements und die Rücksendung der Ergebnisse. Diese Aufteilung ist sehr attraktiv, da man durch den mittleren Tier in der Lage ist, Kontrolle zu haben über die Benutzungsrechte und die Art der Updates der Daten (Bild 2.3.1.1.1b). In dieser Arbeit werden die Three-tier-Architektur und die JDBC/ODBC Bridge zum Zugriff auf die Datenbank verwendet. Java Applet HTML Browser Client HTTP, RMI, CORBA Aufrufe Applikation-Server (Java) Java Applikation Client JDBC DBMS-eigenes Protokoll DBMS Bild 2.3.1.1.1a Server JDBC DBMS-eigenes Protokoll Datenbank Server DBMS Two-tier Modell Bild 2.3.1.1.1b Datenbank Server Three-tier Modell Der Nachteil dieser Anordnung ist, daß auf jedem Rechner, auf dem die Applikation laufen soll, sowohl der ODBC Treibermanager als auch der ODBC Treiber installiert sein müssen. Dadurch ist keine vollständige Plattformunabhängigkeit mehr gegeben. JDBC Applikation / Applet Java JDBC JDBC Driver Manager JDBC / ODBC Bridge ODBC Driver Manager ODBC ODBC Data Access Middleware ... SQL-Datenbanken Bild 2.3.1.1.2 JDBC/ODBC Bridge Da der Datenbankzugriff durch JDBC noch sehr neu ist und sich Java selbst noch häufig ändert, sind zur Zeit nur wenige reine Java-Lösungen auf dem Markt. Die JDBC/ODBC-Bridge sollte also nur als Zwischenlösung betrachtet werden, bis entsprechende Treiber der dritten oder vierten Art verfügbar sind. Diese nur in Java geschrieben Treiber garantieren dann die geforderte Plattformunabhängigkeit. 2.3.2 Java Remote Method Invokation Der folgende Abschnitt stellt den Mechanismus des Methodenfernaufrufs dar. Er wird in der vorliegenden Arbeit zur Kommunikation zwischen Client und Server genutzt. Da sich der englische Begriff remote in diesem Zusammenhang nicht mit einem deutschen Wort exakt darstellen läßt, wird immer dann remote eingesetzt, wenn von einem Methodenfernaufruf die Rede ist oder von den daran beteiligten Elementen. Bei verteilten Systemen ist es erforderlich, daß Programme, die auf verschiedenen Rechnern laufen, miteinander kommunizieren können. Generell sind in Java dafür Sockets vorgesehen, die eine flexible Kommunikation von Port zu Port erlauben. Der Nachteil bei der Verwendung von Sockets ist, daß sowohl der Client als auch der Server über ein Applikation-Level Protokoll die zu versendenden Nachrichten ver- und wieder entschlüsseln müssen. Das Benutzen solch eines Protokolls ist aber unbequem und kann fehleranfällig sein. Die Alternative zur Verwendung von Sockets ist der Remote Procedure Call (RPC). Dieser verhält sich wie ein lokaler Prozedurenaufruf, wobei der Prozedurenablauf nur in einen anderen Prozeß ausgelagert wird, der häufig auf einem anderen Rechner abläuft. Rechner A, Prozeß X Rechner B, Prozeß Y Client Server ... ... Z1 ..., Z2 ..., ... Begin Z3 ..., ... P(Z1, Z2, Z3) Procedure P(X1, X2, X3) Begin Y1 ... , ... ... End End ... ... Bild 2.3.2.1 Remote Procedure Call (RPC) Das RPC Konstrukt paßt aber mit seiner protokollorientierten Kommunikation nicht 100-prozentig zur objektorientierten Struktur der Kommunikation in verteilten Systemen. An dieser Stelle greift die Remote Method Invokation (RMI), d. h. der Aufruf eines remote objects, eines Objektes auf einem anderen Rechner, erfolgt durch ein lokales "Stellvertreterobjekt" oder Stub. Im Gegensatz zu anderen RMI-Systemen wie z. B. CORBA (Common Object Request Broker Architecture) ist Java RMI auf das homogene Umfeld der Java Virtual Machine (JVM) ausgerichtet [RMI97b]. 6 Gründe für den Einsatz von Java RMI • Unterstützung von nahtlosen Fernaufrufen von Objekten auf verschiedenen virtuellen Maschinen • Unterstützung von 'Rückaufrufen' des Applets durch den Server • Integration des Modells des verteilten Objektes in die Sprache Java mit weitestgehender Übernahme ihrer Objekt-Semantik RMI Modell ist einfach zu benutzen und fügt sich 'natürlich' in die Sprache Java ein • Unterscheidung zwischen verteilten und lokalen Java Objektmodellen • Entwicklung von zuverlässigen verteilten Applikationen wird möglichst einfach • Durch Javas Laufzeitumgebung zur Verfügung gestellte Sicherheit wird bewahrt Tabelle 2.3.2.1 2.3.2.1 6 Gründe für den Einsatz von Java RMI RMI Interfaces und Klassen Die Schnittstellen und Klassen, die für das remote Verhalten des RMI Systems verantwortlich sind, sind in den Paketen java.rmi und java.rmi.server definiert. Bild 2.3.3.2 zeigt die Zusammenhänge zwischen diesen Klassen und Interfaces: Interfaces Remote Klassen Implementierung RemoteObject IOException Erweiterung ... RemoteServer Erweiterung RemoteException Erweiterung ... UnicastRemoteObject Bild 2.3.2.2 Zusammenhang zwischen RMI Interfaces und Klassen Alle Schnittstellen mit remote Charakter haben, entweder direkt oder indirekt, als Erweiterung das Interface java.rmi.remote, welches keine Methoden definiert: public interface Remote { } public interface InterfaceName extends Remote{ ... } Die Methoden in einem solchen Interface müssen folgenden Kriterien genügen: • Jede Methode muß die java.rmi.RemoteException zusätzlich zu anderen applikationspezifischen Exceptions (Ausnahmen) aufführen, um die Applikationen robuster zu machen. • Ein RemoteObjekt, als Argument oder als Rückgabewert (direkt oder in ein lokales Objekt eingebunden) übergeben, muß als remote Interface deklariert werden, nicht als die implementierte Klasse. Die RemoteException Klasse ist die Superklasse über alle Ausnahmen, die von RMI zur Laufzeit angeführt werden können. Sie kommt zum Einsatz, wenn der Fernaufruf einer Methode z. B. durch einen nicht erreichbaren Server oder einen Netzwerkfehler nicht ausgeführt werden kann. Die RMI Serverfunktionalität wird von Java durch die Klassen java.rmi.server.RemoteObject und die Unterklassen java.rmi.server.RemoteServer und java.rmi.server.UnicastRemoteObject bereitgestellt. In dieser Arbeit wird das UnicastRemoteObject verwendet, da andere RemoteObjects noch nicht verfügbar sind. Diese Klasse definiert ein einzelnes remote Objekt, dessen Referenzen nur gültig sind, solange der Serverprozeß am Leben ist. Um ein remote Interface zu implementieren, müssen gewisse Regeln beachtet werden: die Klasse • hat als Erweiterung java.rmi.server.UnicastremoteObject, beerbt also RemoteServer und -RemoteObject. • kann eine beliebige Anzahl von remote Interfaces implementieren • kann als Erweiterung für ein anderes remote Interface dienen • kann Methoden definieren, die zwar nicht in der Schnittstelle definiert sind, aber lokal verfügbar sind. 2.3.2.2 RMI Systemarchitektur Das RMI System besteht aus 3 Schichten: • der Stub/Skeleton-Schicht, mit Stubs (Proxies) auf der Client- und Skeletons auf der Serverseite. • der Remote Reference-Schicht, Fernreferenzverhalten wie z. B. der Aufruf eines einzelnen Objekts. • der Transportschicht, Setup und Management von Verbindungen und das Halten von remoten Objekten auf dem richtigen Weg. Applikation Client Stubs RMI System Server Skeletons Remote Reference Layer Transport Bild 2.3.2.3 Architektur des RMI Systems Die Implementierung der Transportschicht ist TCP gestützt. Eine transparenter Transport von Objekten von einem Adreßplatz zum anderen wird mit der Objektserialisation realisiert, die speziell für Java entwickelt wurde. Um zu gewährleisten, daß ein remote Objekt das gleiche Paket an remote Interfaces implementiert wie der Client, wird das dynamische Stub-Laden genutzt. Dieses kommt zum Einsatz, wenn der exakte Stub-Typ dem Client nicht zur Verfügung steht. der Client kann dann auf in Java eingebaute Operatoren zurückgreifen. 2.3.2.3 RMI Sicherheitsmechanismen In RPC Systemen muß der Code von der Client Seite generiert und in den Client eingebunden werden, bevor ein Prozedurenfernaufruf (Remote Procedure Call) erfolgen kann. Die Einbindung kann statisch oder dynamisch zur Laufzeit erfolgen mit Libraries, die lokal oder über das Netzwerk verfügbar sind. In jedem Fall muß der Code für den Client in compilierter Form vorliegen. RMI hat diese Technik ausgebaut, der Mechanismus dynamisches Klassenladen (dynamic class loading) lädt zur Laufzeit die Klassen, die für den Methodenaufruf eines remote Objekts nötig sind: • die Klassen des remote Objekts und die zugehörigen Interfaces • die Stub- und Skeletonklassen • andere Klassen, die direkt von RMI Applikationen genutzt werden, wie z. B. Parameter für oder Rüchgabewerte von remote Objekten. Dynamisches Klassenladen baut auf drei Mechanismen auf: dem Classloader, dem Security Manager und der Objektserialisation. Der Classloader Ein Classloader lädt anfangs alle Klassen und Interfaces, die direkt in der Klasse benutzt werden, zu der der Classloader gehört. Es existieren drei Standardtypen: • der AppletClassLoader, der Applets über das Netz lädt • der Standard Classloader, der über den lokalen Classpath alle direkt gebrauchten Klassen lädt • der RMIClassLoader, der die indirekt genutzten Klassen lädt und zwar in folgender Reihenfolge der Quellen: 1. lokaler Classpath 2. für alle Objekte als Parameter oder Rüchgabewerte die URL, die im Marshal Stream (Byte Strom) kodiert ist und die serialisierten Objekte enthält 3. für Stubs und Skeletons die URL, die durch java.rmi.server.codebase spezifiziert ist. Um alle Klassen und Interfaces laden zu können ist ein sog. bootstrapping client Programm nötig, das den Einsatz z. B. des RMIClassLoaders statt des Standardclassloaders forciert. Dabei laufen folgende Schritte ab: 1. Bilden einer Instanz eines RMISecurityManagers benutzerdefinierten Security Managers oder eines 2. Verwenden der Methode RMIClassLoader.loadClass um die Client-Klasse zu laden mit der Methode newInstance wird eine Instanz des Client gebildet 3. Mit dem Runnable Interface wird die Möglichkeit gegeben, Threads auszuführen 4. Mit der run Methode wird der Client gestartet. z. B.: import java.rmi.RMISecurityManager; import java.rmi.server.RMIClassLoader; public class LoadClient { public static void main() { System.setSecurityManager(new RMISecurityManager()); try { Class cl = RMIClassLoader.loadClass("myclient"); Runnable client = (Runnable)cl.newInstance(); client.run(); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); } } } Ohne diese Technik müssen alle Klassen, die direkte Referenzen zum Client Code besitzen, über den lokalen Classpath erreichbar sein, alle anderen wie Stubs, Skeletons und zu remoten Methodenaufrufen gehörige Klassen können vom RMIClassLoader über das Netz geladen werden. Sobald Klassen in Java vom lokalen Classpath geladen werden, haben sie den Status vertrauenswürdig und unterliegen somit nicht mehr den Beschränkungen des Security Managers. Trotzdem muß ein Security Manager vorhanden sein, wenn ein RMIClassLoader Klassen über das Netzwerk laden will, sonst gibt es die entsprechende Exception. Der Security Manager Der Security Manager muß als erstes im Java Programm gestartet werden, so daß er die folgenden Aktionen regeln kann. Der Security Manager hat die Aufgabe zu Gewährleisten, daß die geladenen Klassen den Java Standard Sicherheitsvorschriften genügen, z. B.: • Überwachen der Aktionen von geladenen Stubs oder Klassen und deren Unterklassen als Teil eines Methodenfernaufrufs durch den Security Manager • Unterstützen von Funktionen wie Klassendefinition und -zugang, d. h. benötigte Klassen für remote Objekte, Argumente und Rüchgabewerte können nachgeladen werden. Die nachgeladene Klasse ist fähig durch RMI Transport initiierte Verbindungen einzugehen • Klassen werden von “vertrauenswürdigen“ Quellen geladen, z. B einem Applet Host. Dieser ist eine sichere Quelle, da ein Applet Netzverbindungen nur zu seinem Wirt herstellen kann. Alle vom Applet genutzten RMI-gestützten Services müssen also auf dem Server liegen, von dem das Applet geladen wurde, d. h. alle remote Objekte, die zum Applet gesendet werden, und die zugehörigen Klassen sind bekannt und müssen nicht über das Netz geladen werden. • Verhinderung des Zugangs zu sensitiven Funktionen. Die Objektserialisation Objektserialisation im Java System ist der Prozeß der Bildung einer serialisierten Repräsentation eines Objektes oder eines Graphen von Objekten. Objektwerte und typen werden serialisiert, um sicherzustellen, daß äquivalente Objekte wiederhergestellt werden können. Deserialisation ist der analoge symmetrische Prozeß. Verschiedene Versionen einer Klasse könne kompatible Streams schreiben und lesen. Objekte, die im Stream gespeichert sind, unterstützen die Schnittstellen Serializable oder Externalizable. Die serialisierte Form eines Java Objektes muß die Java Klasse identifizieren und verifizieren können, aus der heraus der Inhalt des Objektes gespeichert wurde, und diesen Inhalt in einer neuen Instanz wiederherstellen können. Die Ziele für das Serialisieren von Java Objekten sind ([OBSER97]): • einen einfachen schon jetzt erweiterbaren Mechanismus zu haben • Bereitstellen des Java Objekt Typs serialisierten Form des Objektes • erweiterbar sein, um die Persistenz von Java Objekten zu unterstützen • erweiterbar sein, um Marshaling und Unmarshaling zu unterstützen, d. h. das Schreiben in und Lesen von einem Strom • dem Objekt zu erlauben, seinen externes Format zu definieren • benötigte Implementierungen je Klasse nach Bedarf. und sichere Eigenschaften in der Objekt Serialisierung Stream Transport Objekt Deserialisierung Bild 2.3.2.4 Stream Serialisierung und Deserialisierung Sicherheitsmechanismen in der Objektserialisation Das System der Objektserialisation baut darauf auf, daß aus einem Graphen von Objekten ein Bytestrom aufgebaut wird (Serialisation), dieser dann in die Java Umgebung geschickt wird und danach als ein äquivalenter Satz von neuen Objekten mit dem selben Status (Deserialisation) wiederhergestellt wird. Die Sicherheit des Bytestromes außerhalb der Java Umgebung unterliegt dem Betriebssystem, nicht mehr dem Java System. Die Sicherheitsmechanismen von Java sollen verhindern, daß die serialisierten Objekte z. B. durch Viren manipuliert werden können. Gleichzeitig soll das System aber so einfach wie möglich gehalten werden, um das Sicherheitsrisiko zu minimieren. Das geschieht durch folgende Implementierungen: • Nur Objekte, die das Interface java.io.Serializable oder java.io.Extrernalizable implementieren, können serialisiert werden • mit Hilfe der Serialisation können nur neue Objekte geschaffen werden, es kann nicht dasselbe Objekt wiederhergestellt oder überschrieben werden • Objekte, die das Interface Externalizable implementieren, können mit der Methode readExternal mit dem Status public überschrieben werden • Klassen, die während der Deserialisation geladen werden, unterliegen den Standardsi- cherheitsmechanismen, die für alle Klassen in Java gelten. Wichtige Daten, die z. B. die Systemressourcen betreffen, sollten als transient deklariert werden, um eine Deserialisierung und damit einen etwaigen Datenverlust zu umgehen. Der Entwickler kann darüber hinaus klassenspezifische Methoden zur Serialisation schreiben oder den Bytestrom verschlüsseln, um eine Dekodierung und das Lesen des private Status zu verhindern. 2.3.3 Java Security Java Security bietet eine Reihe von Sicherheitsmechanismen an, z. B. digitale Signaturen oder Verschlüsselungsmechanismen. Diese kommen zum Einsatz, wenn Daten gesichert übertragen und geladen werden sollen. In dieser Arbeit ist es jedoch ausreichend, auf die RMI-Sicherheitsmechanismen zurückzugreifen, da der Agentencode lokal vorhanden ist und durch Objektserialisierung referenziert wird. Die neue Java Security API ist eine core API, die aus dem package java.security und den dazugehörigen subpackages java.security.acl und java.security.interface besteht. In erster Linie wird damit eine Kryptologiefunktionalität bereitgestellt, die in Java Applikationen eingebunden werden kann. Der Bereich der Kryptologie ist so angelegt, daß sich ohne Mühe neue Algorithmen hinzufügen lassen. Zum bis jetzt einzigen Algorithmus für digitale Signaturen DSA könnte also ohne weiteres z. B. RSA dazukommen. Spätere Versionen der Security API sollen verstärkt Methoden für sichere verteilte Anwendungen und Unterstützungen der Systemsicherheit enthalten. So sind Block- und Streamverschlüsselung, symmetrische und asymmetrische Verschlüsselung und die Unterstützung von mehrfachen Verschlüsselungen in Arbeit. Zur Zeit sind folgende Sicherheitsmechanismen in der API enthalten: • Digitale Signaturen: Verfügbarer Algorithmus ist DSA. Sowohl das Generieren von Public- / Private-Key Paaren als auch das Signieren und Verifizieren von "eigenwilligen" digitalen Daten ist möglich. • Access Control List: Mechanismus zum Verwalten von Zugriffsberechtigungen von Individual- oder Gruppenbenutzern. Die zugehörige API wird nicht für die interne JDK System Sicherheit verwendet. In den nächsten Ausgaben von JDK soll eine vollständige Kontrolle möglich sein. • Key Management Ein Set von Abstraktionen zum Verwalten von Individual- oder Gruppennutzern und deren Schlüsseln und Zertifikaten. Es ermöglicht den Applikationen das Design eines eigenen Key Management Systems und das Zusammenarbeiten mit anderen Systemen auf einem hohen • Niveau. Spezielle Formate wie X.509 v3 werden in zukünftigen Versionen von JDK verfügbar sein. Überprüfen der Datenintegrität z. B. mit MD5 und SHA-1. Diese Algorithmen, sogenannte one-way hash Algorithmen, sind nützlich bei der Her-stellung von digitalen Fingerabdrücken von Daten, die häufig in digitalen Signaturen oder anderen Applikationen genutzt werden, die einheitliche und nicht veränderbare Identifizierungsmöglichkeiten für digitale Daten brauchen. 2.3.3.1 Java.security.acl Package Das Java Acl Paket liefert alle Klassen, die zum Erstellen, Verwalten und Benutzen einer Access Control List (ACL) nötig sind. Der Einsatz einer ACL wird aber momentan noch nichtvoll von JDK unterstützt. Eine ACL ist eine Datenstruktur, die den Zugriff auf Ressourcen überwacht. Das java.security.acl Paket stellt eine entsprechende Schnittstelle und das sun.security.acl Paket eine Standardimplementierung dieses Interface, mit Spezifikation im java.security.acl Paket, zur Verfügung. Unter einer ACL kann man sich eine Datenstruktur mit vielen ACL Einträgen vorstellen. Jeder Eintrag, vom Typ Interface AclEntry, enthält eine Reihe von Rechten, die einem bestimmten Individual- oder Gruppennutzer zugewiesen sind. Diese Rechte sind entweder positiv oder negativ. Ein positiver Eintrag hat eine Gewährung des Nutzers, eine negative die Ablehnung zur Folge. Eine ACL ist unabhängig von der Authentifikation zur Verifikation eines Nutzers und der Verschlüsselung, die beim Transport von Daten über das Netz verwendet werden. Der Einsatz der ACL erfolgt nach der Authentifikationsphase. Nachdem die Zugangsberechtigung des Nutzers festgestellt worden ist, kann, je nach Eintrag in die ACL, auf die Ressourcen zugegriffen werden. Von diesen Ressourcen ist die ACL unabhängig. Die Access Control List kann damit Auskunft geben darüber, wer in die Nutzerliste eingetragen ist und welche Rechte der jeweilige Nutzer hat. Bei der Kalkulation der bewilligten Rechte gelten folgende Regeln: • Jeder Nutzer kann nur je einen Eintrag haben, positiv und negativ, Mehrfacheinträge sind nicht möglich. • Ist kein Eintrag vorhanden, gilt für den Nutzer die Nullberechtigung oder das null set. • Die positive Netzgruppenberechtigung für einen Nutzer ist die Vereinigung aller positiven Berechtigungen aller Gruppen, zu denen der Nutzer gehört. • Die negative Netzgruppenberechtigung für einen Nutzer ist die Vereinigung aller negativen Berechtigungen aller Gruppen, zu denen der Nutzer gehört. • Sind für einen Nutzer oder eine Nutzergruppe sowohl ein positiver als auch ein negativer Eintrag zu einer Berechtigung vorhanden, werden beide Einträge gelöscht. • Individualberechtigungen überschreiben immer die Gruppenberechtigungen, auch bei verschiedenen “Vorzeichen“. • Angenommen, die Menge aller positiven Berechtigungen aller Gruppen, zu denen ein Nutzer gehört, wäre g1 und analog die Menge der negativen Berechtigungen g2, außerdem sei die positive Individualberechtigung diese Nutzers p1, die negative p2 und die resultierende Gesamtberechtigung bres. Dann läßt sich die resultierende Berechtigung mit b res = ( p 1 + ( g 1 − p 2 )) − ( p 2 + ( g 2 − p 1 )) berechnen. In der folgenden Tabelle sind einige Beispiele zur Verdeutlichung dieser Regeln aufgeführt, dabei sind A, B und C beliebige, voneinander verschiedene Aktionen wie z. B. das Lesen einer Datei (read) oder das Überschreiben (write). G1 und G2 sind die Gruppen, zu denen Nutzer N gehört. Rechte für G1 Rechte für Netzgruppen Individualrechresultierende G2 rechte für N te für N Berechtigung für N positiv negativ A null set B null set A+B null set C null set A+B+C positiv negativ A -C B -A B -C C null set B+C positiv negativ A null set B null set A+B null set C -A B+C positiv negativ A -C C -B A -B B -A B Tabelle 2.3.3.1 Kalkulation der Berechtigungen Der Programmcode für ein einfaches Beispiel sieht folgendermaßen aus: import java.security.acl.*; public class Acl Example { public static void main(String args[]) throws Exception { Principal p1 = new PrincipalImpl(“user1“); Principal owner = new PrincipalImpl(“owner“); Permission read = new Permission(“READ“); Permission write = new Permission(“WRITE“); Group g = new GroupImpl(“group1“); g.addMember(“group1“); Acl acl = new AclIMPL(“exampleAcl“); AclEntry entry1 = new AclEntryImpl(g); entry1.addPermission(read); entry1.addPermission(write); acl.addEntry(owner, entry1); AclEntry entry2 = new AclEntryImpl(p1); entry2.addPermission(write); entry2.setNegativePermissions(); acl.addEntry(owner, entry2); } } Der Nutzer p1 wird der Gruppe g zugeordnet, von den der Gruppe gewährten Rechte read und write wird dem Nutzer allerdings nur read bewilligt. 2.3.3.2 Javakey In Java wird dem Entwickler mit Javakey und JAR die Möglichkeit gegeben, Daten zu signieren oder eine signierte Archiv Datei zu erstellen. Wenn der Agent z. B. auf mehrere Dateien anwächst und/oder über das Netz als Byte Code geladen werden soll, sollte der Code als JAR-Datei und signiert verschickt werden, um vor unbefugten Zugriffen geschützt zu sein. Ein kryptologisch sicherer Signaturalgorithmus bildet aus Daten einer beliebigen Länge und einem private key einen relativ kurzen Bytestring (oft mit fester Größe), die sogenannte Signatur. Sie besitzt folgende Eigenschaften: • durch die Korrespondenz zwischen dem public und dem private key wird die Möglichkeit gegeben, die Authentizität und Integrität von Daten zu verifizieren • die Signatur und der public key geben keine Informationen über den private key preis. • Um Daten zu signieren, ist ein Signaturobjekt notwendig, das den Status UNINITIALIZED (vor der ersten Initialisierung), SIGN und VERIFY haben kann. Für eine Signatur wird das Signaturobjekt mit dem private key initialisiert, für eine Verifizierung mit dem public key. Der Mechanismus der Signatur läßt sich nicht nur auf einzelne Dateien anwenden, sondern auch auf Dateienarchive mit Hilfe des Java Archives JAR. JAR ist ein Dateiformat, das auf dem ZIP Dateiformat basiert. Es wird zum Zusammenfügen von vielen Dateien zu einer einzigen Datei genutzt. JAR ist nach [JAR97] • das einzige Archivformat, das plattformübergreifend ist • das einzige Format das sowohl Audio- und Image- als auch Class-Dateien handhabt • mit existierendem Applet Code ist es rückwärtskompatibel • in Java geschrieben, vollständig erweiterbar, laut Sun ein Open Standard • die bevorzugte Art, Teile eines Applets zu bündeln Generell kann JAR zum Archivieren genutzt werden, doch wurde es primär entwickelt, um die Handhabung von Java Applets und deren Komponenten wie Audio-, Image- und Class-Dateien zu verbessern. Eine signierte JAR-Datei enthält zusätzlich zu den normalen Dateien eine Signatur- und eine Manifest-Datei. Das Manifest ist eine ASCIIDatei, die Meta-Informationen über den Inhalt des Archivs enthält. Für jeden Signierenden gibt es genau eine Signatur-Datei. Nachfolgende Tabelle zeigt die Vorteile einer JAR Datei auf: VORZÜGE DER VERWENDUNG EINES SIGNIERTEN JAR-FILES Durch Bündelung von vielen Dateien zu einer ist nur eine HTTP Transaktion zum Laden eines Applets in einen Browser nötig, d. h. die Zahl der Verbindungen und damit die Ladezeit der zugehörigen Webseite werden minimiert. Das JAR-Format unterstützt Datenkompression, dadurch wird die Dateigröße minimiert und damit auch die Ladezeit über das Netz. Individuelle Einträge in die JAR-Datei können vom Applet-Autor mit einer digitalen Signatur versehen werden und damit ihre Herkunft authentisieren. Tabelle 2.3.3.2 Vorzüge eines signierten JAR-Files Um eine JAR-Datei zu generieren und mit Javakey zu signieren, sind folgende Schritte nötig (ausführliche Anleitung in [JKEY97]): 1. Der Pfad zum java/bin-Verzeichnis muß korrekt gesetzt sein mit % setenv PATH ~/java/bin:$PATH 2. Eine Identität muß geschaffen werden mit % javakey -cs “Pseudonym“ true Diese Identität ist der Name für den Signierenden, sie lebt in der Identitätsdatenbank für die jeweilige JDK Version. 3. Generieren eines Schlüsselpaares für die Identität % javakey -gk “Pseudonym“ DSA Pseudonym_priv 512 Pseudonym_pub Javakey benötigt den Namen des Signierenden, “Pseudonym“, den Namen des Algorithmus (zur Zeit ist DSA der einzige durch JDK unterstützte Algorithmus) und die Größe des zu benutzenden Schlüssels (in diesem Beispiel 512). Pseudonym_pub und Pseudonym_priv sind die Dateien, in denen die jeweiligen Schlüsselpaarhälften gespeichert werden. Der private key signiert die Datei, der public key verifiziert die Signatur. Ein DSA Schlüsselpaar kann nur zum Signieren verwendet werden, RSA dagegen kann mit einem passenden Verschlüsselungsalgorithmus auch zur Verschlüsselung benutzt werden. 4. Generieren eines Zertifikats % javakey -gc cert_directive Die existierende Datei cert_directive wird kopiert und modifiziert (die Argumente sind in [JKEY97] beschrieben). Das Zertifikat kann dann außerhalb der Identitätsdatenbank in dieser Datei gespeichert werden. 5. Schaffen einer JAR-Datei % jar cf JarfileName.jar ClassName.class Das Toolwerkzeug dafür ist jar, das an JDK1.1 gekoppelt an die Entwickler verteilt wird und in seiner Syntax der tar (Tape ARchive)Syntax gleicht. 6. Signieren der Jar-Datei durch die sign_directive Datei % javakey -gs sign_directive JarfileName.jar Für die Signierung wichtige Argumente (die Argumente sind in [JKEY97] beschrieben) sind in der sign_directive Datei als Name/WertPaare enthalten (analoge Paare in certificate_directive). Da das Verketten von Zertifikaten zur Zeit noch nicht unterstützt wird, muß das Argument der Zertifikatsverket tungstiefe zu Null gesetzt werden chain = 0. 7. Informationen über das geschaffene System: % javakey -li Pseudonym liefert Informationen über die Identität “Pseudonym“. % javakey -ld gibt detaillierte Auskunft über die vollständige Identitätsdatenbank. % jar tvf JarfileName.jar hat die Auflistung des Inhalts der Jar-Datei zur Folge. Die Applikation oder das Applet, die signierte Dateien laden müssen, können die Signatur des geladenen Codes verifizieren. Das geschieht mit der Methode java.security.-Signature.verify(byte[]). Die Signatur sollte X.509 verschlüsselt sein. Ein Aufruf der Methode versetzt das Signaturobjekt durch den Aufruf von initVerify(PublicKey) in den Status, in dem es vorher initialisiert wurde. Das bedeutet, das Objekt ist dann bereit zur Verifizierung einer anderen Signatur derselben Identität. 3. Agenten In diesem Abschnitt wird der Versuch einer formalen Definition eines Software Agenten vorgestellt, die die Abgrenzung zu einem normalen Programm aufzeigt. 3.1 Formale Definition eines Agenten Da der Begriff des Agenten von verschiedenen Fachrichtungen unterschiedlich interpretiert wird, ist es schwierig, eine geschlossene, fachübergreifende Definition zu finden. Grundsätzlich ist ein Agent jemand, der stellvertretend für jemand anderen eine Aufgabe erledigt. Ein Software Agent ist ein Programm, das fähig ist, während seiner Ausführung seinen Wirt zu wechseln, ohne seinen inneren Zustand zu ändern. Das erlaubt ihm, die ihm aufgetragenen Aufgaben lokal zu erledigen. Das hat den Vorteil, daß nur der Programmcode zu den zu verarbeitenden Daten gebracht werden muß und nicht die großen Datenmengen zum Programm verschoben werden müssen. Software Agenten sind durch verschiedene Merkmale gekennzeichnet, die in Tabelle 3.1.1 zusammengestellt sind. MERKMAL BEDEUTUNG Reaktion Antwort auf Veränderungen der Umwelt, „wahrnehmen und handeln“ Autonomität Ausübung von Selbstkontrolle Zielorientierung Aktionen sind nicht nur Antworten auf Umweltveränderungen, sondern zielgerichtet Zeitkontinuietät zeitkontinuierlich ablaufender Prozeß Kommunikationsfähigkeit kommuniziert mit anderen Agenten, eventuell auch in Form von Personen, ist "sozialfähig" Lernfähigkeit Wechsel des Verhaltens ist abhängig von vorhergegangenen Erfahrungen, "adaptiv" Mobilität Fähigkeit sich selbst von einem Rechner zum anderen zu transportieren Flexibilität Handlungen sind nicht fest vorgeschrieben Charakter glaubwürdige "Persönlichkeit" und mögliche emotionelle Zustände Tabelle 3.1.1 Agentenmerkmale Aufgrund verschiedener dieser Merkmale lassen sich Agenten bestimmten Klassen zuordnen, deren Aufteilung jedoch nicht zwingend ist (Bild 3.1.1). Um die große Vernetzung des Internets nutzen zu können, werden aus den statischen Agenten mobile Agenten, die über das Netz wandern können. Ein bevorzugtes Einsatzgebiet der mobilen Agenten sind auch Umgebungen mit schwacher Verbindung (z. B. drahtlos) und/oder hohem Datenvolumen. Eine weitere Möglichkeit ist der Einsatz in electronic commerce (elektronische Märkte) oder die Bereitstellung von elektronischen Diensten. 3.2 Mobile Agenten Mobile Agenten sind Objekte, die zusätzlich zum Code (steuert das Verhalten, welches durch Interfaces repräsentiert wird) und Daten wie stationäre Programme auch einen Migrationsplan und ein Stadium zur Durchführung der Aufgabe haben. Die mobilen Agenten sind somit Dienstleistungsprogramme, die auf verschiedenen Rechnern Informationen, die zur Erledigung ihrer Aufgaben nötig sind, zusammensuchen oder deren Dienste in Anspruch nehmen. Agent biologischer Agent Computer Agent Software Agent Künstliche Intelligenz Agent anwendungsspezifischer Entertainment Agent Agent mobiler Agent Robotik Agent Virus ... mobiler Agent ... Bild 3.1.1 Agentenklassifikation Die Agenten leben in einer sogenannten Agentenwelt, eine Umgebung , die die Sicherheit der Agenten und der Rechner gewährleisten soll (Bild 3.1.2). Spezielle Agenten sind dabei die Trader-Agenten, die die Vermittlung von Diensten der jeweiligen Rechner an die User-Agenten, die Stellvertreter der Nutzer, übernehmen. Rechner Rechner TraderAgent UserAgent UserAgent UserAgent Bild 3.1.2 Agentenwelt Aus der Mobilität der Agenten ergeben sich folgende Problemstellungen, die bei der Erstellung eines Agentenszenarios beachtet werden müssen [FUENF97]: • Im Bereich der Betriebssystemunterstützung: Welche zusätzlichen Funktionen werden benötigt, um die Agentenwelt effizient zu gestalten, z. B. Bereitstellung von Ressourcen, Abrechnungen, QoSGarantien, ... • Im Bereich der Agentenwelt: • Heterogenität: Die Agenten müssen in einer Sprache formuliert werden, die plattformunabhängig ist, um auf allen Rechnern ausgeführt werden zu können. Um auch den Sicherheitsanforderungen gerecht zu werden, hat es sich gezeigt, daß Agenten in einer Interpretersprache zu erstellen sind. Damit lassen sich Übergriffe auf sicherheitsrelevante Systemressourcen schon durch den jeweiligen Interpreter reglementieren. Die Agentensprache ist noch nicht gefunden, zur Zeit gebräuchlich sind u. a. Tcl oder Java (Sun), welche in dieser Arbeit verwendet wird. • Kommunikation und Kooperation zwischen Agenten: Um Informationen austauschen zu können, sollen Agenten miteinander kommunizieren können. Dabei sind aber nicht nur einfache statische Übermittlungen gefragt, die über jeweils bekannte Dienste in einem ähnlichen Auftrag informieren, sondern im Hinblick auf den elektronischen Markt sind auch dynamische Vermittlungsprotokolle zwischen den Traderagenten und deren Kunden gefragt. Für die Kooperation zwischen den Agenten werden Kooperationsprotokolle gebraucht, die auch bei in verschiedenen Sprachen programmierten Agenten funktionieren. • Migration (Wanderung) des Agenten: Man kann im Moment zwischen lowlevel Prozeßmigration und highlevel Agentencodemigration unterscheiden. Erstere ist transparent für den Agentencode und damit eine elegante Lösung. Die zweite Variante ist besonders einfach, da das Programm am neuen Bestimmungsort von Neuem gestartet wird. Welche Migration für welche Agenten die geeignete ist, muß noch erforscht werden. • Sicherheit des Agenten und des Wirtssystems: Ein Verfahren, wie der Agent vor dem Wirt geschützt werden kann, ist noch kaum erforscht. Dabei ist der Agent zahlreichen Attacken durch den Wirt ausgesetzt. So kann der Server die Kontrolle über Ausführen, Status etc. des Agenten haben. Auch kann er den Agentencode manipulieren, die im Agenten enthaltenen Daten (und damit auch Keys) lesen, den Agenten in die falsche Richtung leiten, ihn killen oder clonen, ihn modifizieren und schließlich über die Analyse des mobilen Agenten ein Profil des Senders erstellen. Der Agent hat aber keine wirkliche Chance zu erkennen, ob der Server ihn manipuliert. Die Verwendung der digitalen Signatur allein ist nicht sinnvoll, da sich die Daten, die der Agent mit sich trägt, wie z. B. über seinen Status, häufig ändern. Zusätzlich sollten die Teile des Agenten, die dem Server nicht zugänglich sein sollen, verschlüsselt werden. Durch Public-Key Verfahren lassen sich aber Authentizität und Integrität des transferierten Agentencodes überprüfen. Das Wirtssystem kann sich durch Verschließen seines Interpreters gegenüber der Agentensprache schützen. • Im Bereich der Agentenplattformen: Sie stellen die grundlegende Agentenweltfunktionalität zur Verfügung und dienen dazu, Agentenwelten einfach erstellen zu können. Hauptforschungsschwerpunkte sind hier das Identifizieren von Bausteinen, z. B. verschiedene Ausprägungen von Migration, Kommunikation oder Sicherheit und das Festschreiben von Standards. 3.3 Agentensprachen Bei den Agentensprachen ist zwischen den Kommunikationssprachen und den Sprachen zur Programmierung von Agenten zu unterscheiden. 3.3.1 Kommunikationssprachen Einsatzmöglichkeiten für Kommunikationssprachen sind: • Verwendung als Sprache für eine Applikation, die mit intelligenten Systemen in Wechselwirkung steht • Zwei oder mehr intelligente Systeme teilen Wissen miteinander, um in Kooperation Probleme zu lösen. In dieser Arbeit werden diese Sprachen nur der Vollständigkeit halber aufgeführt. Dem Agenten zu ermöglichen, z. B. mit anderen Agenten zu kommunizieren und Wissen zu tauschen ist Aufgabe der nachfolgenden Projekte. KQML (Knowledge Query and Manipulating Language) KQML ist eine Sprache und ein Protokoll für den Informations- und Wissensaustausch. Es ist Teil eines größeren Projekts, des ARPA Knowledge Sharing Effort [KQML97], das sich zum Ziel gesetzt hat, Techniken und Methoden zu entwickeln, die die Bildung von Wissensbanken erlauben, die wiederverwendbar und für viele zugänglich sind. KQML ist einerseits ein Format für Nachrichten, andererseits ein Protokoll, das den Wissensaustausch zwischen Agenten zur Laufzeit unterstützt [KQML97]. KIF (Knowledge Interchange Format) KIF ist eine computerorientierte Sprache zum Austausch von Informationen und Wissen zwischen verschiedenen ungleichen Programmen. Sie besteht aus einem Gerüst mit aussagekräftiger Semantik und umfassende Logik. Durch Sie werden Informationen über Wissen bereitgestellt [KIF95]. 3.3.2 Programmiersprachen Die Programmiersprachen werden zur Schaffung des Agentenprogrammcodes verwendet. Im vorliegenden Projekt wird Java (siehe Absatz 2.3) benutzt. Andere wichtige Programmiersprachen werden im folgenden vorgestellt. Tcl (Tool Comand Language) Tcl stellt zwei Dinge dar: eine Scriptsprache und ein einen Interpreter für diese Sprache. Tcl und die zugehörige graphische Benutzerschnittstelle Tk wurden von Professor Ousterhout in Berkely an der Universität von Kalifornien entwickelt. Tcl wurde so designed, das es bevorzugt mit C als Systemprogrammiersprache zusammenarbeitet. Mit dem großen Erfolg von Java wurde Tcl aber auch an die JVM angepaßt. Das Design als Scriptsprache bietet einige Vorteile: • die Entwicklung ist schnell, es gibt keine langen Compilierungszeiten • die Benutzerschnittstelle ist klar getrennt vom Rest der Applikation, so daß der Entwickler sich erst auf die Applikation und dann auf das Interface konzentrieren kann. • Tcl ist C sehr ähnlich, es ist daher leicht möglich, Tcl durch selbstgeschriebene CRoutinen zu erweitern. Save-Tcl Safe-Tcl ist das Security-Modell von Tcl. Es wurde von Nathaniel Borenstein und Marshall Rose entwickelt, um den sicheren Transport von Programmen per Email zu ermöglichen. Safe-Tcl führt nicht vertrauenswürdige Skripte in einer speziellen Kontrollumgebung, der padded cell, nochmals aus, wobei es das Skript in dem, was es tut, einschränkt . Diese Modell ähnelt dem kernel-space/user-space Mechanismus. In einer Applikation können verschiedene Tcl-Interpreter laufen. Ein vertrauenswürdiger Interpreter wird master interpreter genannt und hat alle Rechte. Ein nicht vertrauenswürdiges Skript läuft in einem separaten Interpreter, dem slave interpreter oder der padded cell, ab ohne riskante Aktionen wie das Lesen und Schreiben von Dateien zuzulassen. Ein anderer implementierter Mechanismus, der safe call, erlaubt dem slave interpreter Forderungen an seinen master zu stellen, z. B. Zugang zu einer Datei zu bekommen. Die safe calls unterstehen der vollständigen Kontrolle durch den master interpreter. Safe-Tcl erlaubt zwar Code Migration, ist aber kein vollständiges transportables Agentensystem. Telescript Telescript wurde bei General Magic Inc. als kommerzielle Sprache zur Programmierung von Agenten entwickelt. Es ist eine objektorientierte Interpretersprache. Bei Aufruf der Methode live wird der Agent geschaffen. Die Softwareagenten migrieren durch das Kommando go. Dadurch wird der gesamte Agent zu einem anderen Rechner transferiert. Die Ausführung des Programmcodes wird mit dem Status direkt nach der Migration, auf dem neuen Wirt fortgesetzt. Ein Telescript Server akzeptiert und authentifiziert ankommende Agenten auf jeder Netzwerkseite. Telescript wird im Sony Magic Link, dem Motorola Envoy und dem AT&T PersonalLink Network eingesetzt. Es wurde bis jetzt noch nicht auf anderen Plattformen implementiert. 3.4 Der Datenbankzugriff durch einen Agenten Das Ziel der vorliegenden Arbeit zum Thema “Realisierung von Teilen eines Systems für den hierarchischen Zugriff auf multimediale Datenbanken mittels wandernder Agenten in einem Intranet“ war ursprünglich, auf eine Datenbank durch Methodenfernaufrufe und sichere mobile Agenten zuzugreifen. Da die vollständige Implementierung dazu den zeitlichen Rahmen gesprengt hätte, wurde der Zugriff durch Methodenfernaufrufe von Serverobjekten und einen statischen Agenten realisiert. Theoretisch wurden aber die Sicherheitsmechanismen untersucht, die bei Einsatz eines Agenten sinnvoll sind 1 , aber von Java noch nicht unterstützt werden oder noch nicht verfügbar sind. Das vorliegende System basiert auf dem RMI System. Deshalb wurden in dieser Arbeit die RMI Sicherheitsmechanismen verwendet. Als erstes ist der RMISecurityManager zu nennen, der einzige in RMI verfügbare. Durch seine Überwachung der zu ladenden Klassen stellt er einen Sicherheitsstandard für Applikationen bereit. Desweiteren sind die Sicherheitsmechanismen der Objektserisalisierungzu erwähnen, die schon im Kapitel Java RMI beschrieben wurden. 3.4.1 Architektur Die Systemarchitektur basiert auf der RMI Systemarchitektur (Bild 3.4.1.1). Das bedeutet, daß der Client als Applikation über die drei Schichten Stub-/Skeleton-Schicht, 1 siehe Kapitel 2.3.2 Java RMI und 2.3.3 Java Security Remote Reference-Schicht und die TCP gestützte Transport-Schicht mit dem Server kommuniziert. Die Programmarchitektur entspricht dem Three-tier-Modell (Bild 3.4.1.2). Das remote Objekt AgentCallObjekt wird durch den Client registriert und steht danach dem Server als lokales Objekt zur Verfügung. Es findet ein Methodenfernaufruf vom Wirt des Clients in der ersten Ebene, wahlweise über ein GUI (Graphical User Interface) oder durch Starten des Clients in einem Fenster, zum Wirt des Servers in der mittleren Ebene statt. Dieser lädt den lokal vorhandenen, durch den Client parametrisierten Agentencode und führt ihn aus. Dieser stellt dann die Verbindung zur Datenbank her und führt die SQL-Statements aus. Ein weiterer Methodenaufruf stellt dem Client die Suchergebnisse zur Verfügung, die entweder im GUI oder am Bildschirm ausgegeben werden können.. Applikation RemoteClient Client (Java) RemoteServer RMI RemoteServer_Stub RemoteServer_Skeleton Server (Java) Remote Reference Layer JDBC Transport ODBC DBMS RMI System Bild 3.4.1.1 Systemarchitektur Programmarchitektur Bild 3.4.1.2 Das Scenario ist in Bild 3.4.1.3 dargestellt. Der Agentencode wird auf der Serverseite parametrisiert und zu den Datenbanken geschickt, bevor er zum Client zurückkehrt. Da zur Zeit der Agent nur per Referenz übergeben wird, ist der Agent noch nicht mobil. Mit einem geeigneten selbstentwickelten ClassLoader sollte es aber möglich sein, den gesamten Agentencode zu übertragen, so daß er auf der Serverseite nicht mehr lokal vorhanden sein muß. Da dann nicht mehr nur der Agent serialisiert wird, sondern der gesamte Code des Agenten vom Netz geladen wird, können dann die zusätzlichen Sicherheitsmechanismen von Java Security zum Einsatz kommen. Der Agent wäre dann ein wirklich mobiler Agent. Bild 3.4.1.3 Architektur des Datenbankzugriffs durch RMI 3.4.2 Verwendete Sicherheitsmechanismen Agenten Param eter S e ria lis ie ru n g lo k a l v o rh a n d e n Agenten Code Server Agent lo k al v o rha n de n Agenten Code Client Agenten Param eter re s u ltA re s u ltB C lientseite Netz S e ria lis ie ru n g D atenb ank B Client re s u ltA re s u ltB D e s eria lis ie ru n g Agenten Param eter re s u ltB Datenbank B Serverseite re s u ltA B enutzeroberfläche D e s eria lis ieru n g D atenb ank A re s u ltA Datenbank A Agent re s u ltA re s u ltB Agent Server re s u ltA re s u ltB Agent Im Rahmen der vorliegenden Arbeit wurden die Sicherheitsmechanismen verwendet, die zur Zeit verfügbar und für die vorliegende Architektur relevant sind. Für die Sicherheit des Wirts wird durch die RMI Security gesorgt. Da das Java Security Paket noch nicht vollständig verfügbar und unterstützt ist, konnte der Zugriff zur Datenbank noch nicht sicher gestaltet werden. Da Signaturen oder Passwörter zur Zeit noch nicht verschlüsselt verschickt werden können, ist deren Beitrag zum Schutz der Daten in der Datenbank minimal. Der RMISecurityManager setzt alle Funktionen, außer die der Klassendefinition und des Klassenzugriffs für den mit einem Classloader geladenen Code, außer Kraft. Durch die Restriktionen, denen die geladenen Klassen unterliegen, wird verhindert, daß die Sicherheit der betroffenen Applikation gefährdet wird durch illegale Zugriffe z. B. auf den Prozeßablauf. Ist der RMISecurityManager nicht installiert, werden von RMI nur lokale Klassen geladen (definiert durch den CLASSPATH). In Tabelle 3.4.1 sind die im RMISecurityManager definierten Methoden mit ihren Auswirkungen dargestellt. RELEVANTE SICHERHEITSASPEKTE METHODE Geladene Klassen dürfen keine Classloader schaffen oder Methoden von ClassLoader ausführen. CheckCreateClassLoader Geladene Klassen dürfen keine threads oder threadgroups manipulieren. CheckAccess Geladene Klassen dürfen nicht die VM beenden. CheckExit Geladene Klassen dürfen keine dynamic libraries verbinden. CheckLink Geladene Klassen dürfen keine Prozesse aufspalten. CheckExec Geladene Klassen haben keinen Zugang zu Systemeigenschaften, außer die Eigenschaft ist auch eine RMI Eigenschaft mit Status true. CheckPropertiesAccess Kann die geladene Klasse eine Datei lesen? Das Lesen einer Datei durch eine geladene Klasse ist nicht gültig, außer es geschieht über eine Deskriptor-Socketverbindung, die dann anderen Beschränkungen unterliegen kann. CheckRead Kann die geladene Klasse eine Datei schreiben? Geladene Klassen dürfen nur über eine Socketverbindung schreiben. Deskriptor- CheckWrite Kann die Datei (mit dem spezifizierten systemabhängigen Namen) gelöscht werden? CheckDelete Klassen, die für den Moment geladen werden, können keine Ports abhören. CheckListen Klassen, die für den Moment geladen werden, können keine Verbindungen über Ports akzeptieren. checkAccept Darf der laufende Ausführungskontext IP Multicast verwenden? Geladene Klassen können Verbindungen herstellen über RMI Transport Geladene Klassen dürfen Fenster für Warnungen aufmachen. Hat eine geladene Klasse Zugang zu einem Package? Kann eine geladene Klasse Klassen in einem Package definieren? Kann eine geladene Klasse eine netzbezogene ObjectFactory setzen. Von geladenen Klassen darf nicht gedruckt werden. Darf der Client auf das System Clipboard zugreifen (geladene Klassen dürfen nicht)? CheckMulticast checkConnect checkTopLevelWindow CheckPackageAccess CheckPackageDefinition checkSetFactory checkPrintJobAccess checkSystemClipboardAccess Kann der Client auf die AWT Event Queue zugreifen? checkAWTEventQueueAccess Hat der Client reflektierenden Zugang zu einem Mitglied (member)? checkMemberAccess Geladene Klassen dürfen keine Security Provider Operationen ausführen. checkSecurityAccess Tabelle 3.4.1 Sicherheitsaspekte des RMISecurityManagers 3.4.3 Der Server RemoteServer Stubs und Skeletons, die die Verbindungen des Servers zum Netz realisieren, lassen sich mit dem rmic Compiler durch % rmic ServerClassName generieren. Das Skeleton Interface wird benutzt bei der Implementierung von Skeletons, die mit dem rmic Compiler generiert wurden. Ein Skeleton für ein remote Objekt ist eine Einrichtung der Serverseite, die die Aufrufe zum aktuellen registrierten remote Objekt weiterleitet. Es stellt also die Verbindung zwischen dem Marshalstream und dem remote Objekt her. Die Methode dispatch handhabt das Lesen der Argumente vom Stream, ruft Methoden im aktuellen remote Objekt auf und schreibt die Rückgabewerte wieder in den Stream. Die Methode getOperations gibt ein Array zurück, das Deskriptoren für die Operationen der Methoden des Objektes enthält. Stubobjekte hingegen sind Stellvertreterobjekte, die exact dieselben remote Interfaces unterstützen wie das aktuelle remote Objekt. Sie werden statt der remote Objekte an den Server übergeben. Der Server erweitert das UnicastRemoteObject. Diese Klasse unterstützt eine aktive Punkt-zu-Punkt Objektreferenz unter Verwendung von TCP-basierten Streams. Damit erhält der Server folgende Eigenschaften: • Referenzen sind nur solange gültig, wie der das remote Objekt schaffende Prozeß aktiv ist • der Transport basiert auf einer TCP-Verbindung • Aufrufe, Parameter und Rückgabewerte Kommunikation zwischen Client und Server. nutzen ein Stream-Protokoll Als erstes wird in der main()-Methode der RMISecurityManager installiert. zur System.setSecurityManager(new RMISecurityManager()); Der Server RemoteServer stellt die im Interface definierten Methoden callAgent(AgObject) und sendRes(AgObject) zur Verfügung, auf die der Client durch Fernaufrufe zugreifen kann. In der Methode callAg ist die serialisierte Referenz auf die Datei DbAgent.class als Objekt ist mit inputFile = agent.getObject(); gegeben. Der Klassencode ist in dieser Arbeit lokal vorhanden und wird durch die Parameter, die vom Client geschickt wurden, initialisiert, so daß die Klasse vom Server durch inputFile.run(); geladen werden und eine neue Instanz gestartet werden kann. Damit stellt der Server die Verbindung zur Datenbank her und läßt dann die Sql-Statements ausführen, je nach Benutzereingaben. Danach wird das Objekt wieder per Referenz zurückgeschickt. Das geschieht mit der Methode sendRes. Der Inhalt des Ergebnisvektors, den der Agent während des Datenbankzugriffs mit den Suchergebnissen anlegt, wird serialisiert und in einen Stream geschrieben os1.writeObject(resultvec1); Im Server wird er aus dem Stream gelesen und deserialisiert, in einen Vector geschrieben und an den Client durch RMI zurüchgegeben Vector v = (Vector) is.readObject(); vector.retVector(v); return vector; 3.4.4 Der Client RemoteClient Die main()-Methode des Client behandelt alle Details des Server Setups. Zuerst wird der einzige für RMI verfügbare Security Manager RMISecurityManager installiert. System.setSecurityManager(new RMISecurityManager()); Der Client kann über das AgInterface auf die darin definierten Methoden der Klasse AgObject zugreifen. Mit Naming.lookup werden die remoten Objekt DatabaseAgent und Result registriert. Damit sind sie für den Server faßbar. Sobald das remote Objekt zugänglich ist, verhält es sich wie ein lokales Objekt, mit dem Unterschied der RemoteException als Fehlermeldung. Dieser Vorgang ist in Bild 3.4.3.1 dargestellt. Registrieren des Objektes Naming.lookup Client Server Interface neue Instanz bilden Object quasilokaler Zugriff Name für remote Objekt(e) Bild 3.4.3.1 Objektregistrierung und -aufruf AgInterface intface = (AgInterface) Naming.lookup(“rmi://pc278.igd.fhg.de:1099/startAgent“); Naming.lookup(“rmi://pc278.igd.fhg.de:1099/getResult“); Gleichzeitig wird TCP/IP als Transportprotokoll durch rmi:// und der gewünschte verbindungspartner durch pc278.igd.fhg.de spezifiziert. Mit AgObject getObject = new AgObject(sendFile); AgObject retObject = serv.callAg(getObject); AgObject getVector = new AgObject(vc); AgObject retVector = serv2.sendRes(getVector); werden die Methoden, die durch AgObject und AgInterface definiert sind, parametrisiert und aufgerufen (Bild 3.4.3.2). Parameter Objektcode Parameter Parameter Objektcode Objektcode Wirt A Wirt B Bild 3.4. 3.2 Parameterserialisierung 3.4.4 Das Interface AgInterface Wenn der Client RemoteClient das entfernte Objekt AgObject kontaktiert, wird eigentlich das zugehörige Interface AgInterface angesprochen. Das zieht die Verbindung zum lokalen Stub RemoteServer_Stub nach sich, der seinerseits die Verbindung über das Netz zum Server übernimmt. public interface AgInterface extends remote { Das RemoteInterface erweitert das Interface java.rmi.Remote. In diesem Interface sind die Methoden definiert, die sowohl dem Server (als der das Interface implementierenden Klasse) als auch dem Client zur Verfügung stehen. Zur Zeit sind das die Methoden callAg() und sendRes(), mit denen die AgObject callAgent(AgObject agent) throws RemoteException; AgObject sendRes(AgObject vector) throws RemoteException; Klasse Agent.class geladen und dann ausgeführt wird (callAg()) und das Ergebnis zurüchgegeben wird (sendRes()). 3.4.5 Das remote Objekt AgObject Das remote Objekt AgObject implementiert das Interface Serializable und ist damit serialisierbar. Es definiert Methoden, über die durch das AgInterface vom Client aus zugegriffen werden kann. public File getObject() { ... } public void retObject(File f) { ... } public Vector getVector() { ... } public void retVector(Vector v) { ...} Die Methoden getObject() und retObject() senden das Objekt vom Typ File per Referenz zum Server und erhalten es nach Ausführung zurück. Die Methoden getVector() und retVector() senden einen leeren Vektor zum Server und erhalten einen gefüllten zurück. 3.4.6 Die Verbindung zur Datenbank Mit JDBC wurde der plattformunabhängige Zugriff auf die Datenbank programmiert. Die dazu aufzurufenden Methoden korrespondieren mit den logischen Operationen, die spontan assoziiert werden beim Stichwort “Daten aus einer Datenbank holen“: • • • Verbindung zur Datenbank herstellen - Connect, wird mit java.sql.Connection realisiert ein Statement bilden - Statement, Java enthält die Containerklasse java.sql.Statement, um Sql-Statements auf einer beste henden Verbindung auszuführen. eine Abfrage durchführen - Query • das Ergebnis erhalten - Result Set, java.sql.ResultSet, kontrolliert den Zugriff auf die Ergebnisse eines Statements. Um eine Datenbank abfragen zu können, sind Treiberobjekte nötig, die datenbankspezifisch sind. Ein Treiberobjekt reigistriert sich selbständig bei dem von JDBC bereitgestellten Treibermanager während der Ladezeit. Das Laden kann mit der Methode Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“); forciert werden, wobei in dieser Arbeit ein JdbcOdbc-Treiber verwendet wird. Um sich mit einer Datenbank zu verbinden oder sie zu öffnen, muß eine Datenbank URL existieren. Darin wird spezifiziert 1. daß JDBC verwendet wird, durch jdbc 2. das Subprotokoll, das den Namen des Datenbanktreibers enthält. Bei Gebrauch der Jdbc/Odbc Bridge bedeutet das odbc 3. die Datenbankidentifizierung, meist ein logischer Name, der einen Zusammenhang zwischen der Datenbank und dem physikalischen Verzeichnis herstellt, in dem die Da-tenbank sich befindet. In dieser Arbeit FhG und ThD. String url1 = “jdbc:odbc:FhG“; String url2 = “jdbc:odbc:ThD“; Die Methode DriverManager.getConnection() stellt die Verbindung her (falls vorhanden mit Benutzernamen und Password) und liefert ein Verbindungsobjekt, daß zur Abfrage der DB verwendet wird. Connection con = Drivermanager.getConnection(url, user, password); Die Klasse Agent.class öffnet die Datenbanken und sucht wahlweise nach bestimmten Attributen eines Mitarbeiters wie Namen, Telefonnummern, Projekten, Bildern oder nach allen Attributen (bei Datenbank FhG) oder analog nach allen oder bestimmten Attributen eines Studenten (bei Datenbank ThD). Das Passwort und der Username sind optionale Parameter, die vom Administrator der jeweiligen Datenbank zum Schutz vor unbefugter Vrbindung von außen vergeben werden, sie sind für eine Verbindung mit der Datenbank aber nicht zwingend notwendig. 3.5 Andere Projekte über Mobile Agenten In diesem Abschnitt werden Projekte vorgestellt, die eine ähnliche Thematik zum Inhalt haben wie die vorliegende Arbeit. ARA (Agents for Remote Action) Ara ist ein Projekt der AG Systemsoftware des Fachbereichs Informatik an der Universität Kaiserslautern. Ara stellt eine Plattform zur portablen und trotzdem sicheren Ausführung mobiler Agenten in heterogenen Netzen dar. Das Ziel ist, die volle Funktionalität der Agenten zur Verfügung zu stellen und dabei etablierte Programmiermodelle und -sprachen weitmöglichst zu erhalten. Konzepte der Anwendungsebene wie Agentenkooperationsmuster, intelligentes Verhalten, Benutzermodellierung und ähnliches spielen dabei eine eher untergeordnete Rolle. Das Programmiermodell von Ara besteht aus Agenten , die sich selbständig an oder zwischen Orten bewegen, wo sie vorhandene Dienste (vom Wirt oder anderen Agenten bereitgestellte) nutzen, um ihre Aufgaben zu erfüllen. Da ein Ort eine physische Größe eines Wirtsrechners ist, kann der Agent lokalen Sicherheitsbeschränkungen, sog. Allowances, unterliegen. Eine globale Allowance geht vom Auftraggeber aus. Die Systemarchitektur besteht aus einem Kern und mehreren Prozessen, den Agenten. Das gesamte System läuft dabei auf einem unmodifizierten Wirtsbetriebssystem ab. In Ara ist eine Schnittstelle zur Adaption von Interpretern der gängigsten Programmiersprachen definiert, so daß grundsätzlich jede interpretierbare Programmiersprache bei der Programmierung von mobilen Ara Agenten verwendet werden kann. Davon unabhängig können alle Agenten auf einem Knoten durch den Kern sowohl mit dem Wirtssystem als auch untereinander als Client und Server miteinander kommunizieren. Der Kern als Sicherheitsmanager regelt die Authentisierung von Agenten (in Arbeit) und die Autorisierung und Abrechnung von Betriebsmittelzugriffen. Außerdem bietet er lowlevel Dienste an, während highlevel Dienste auf höherer Ebene von Server-Agenten angeboten werden. Die Migration der Agenten kann jederzeit während seiner Ausführung geschehen, während der Migration bleibt der Zustand des Agenten erhalten. TACOMA Tacoma wird gemeinsam an der Cornell Universität, New York und der Universität von Tromsø in Norwegen entwickelt. Die Schwerpunkte der Forschung liegen hier bei Heterogenität, Fehlertoleranz, Sicherheit und Management Verteilung. Tacoma unterstützt je nach Version Agenten, die in Tcl, C, Perl, Python und Scheme (Elk) geschrieben sind. Zur Zeit wird an StormCast gearbeitet, einem Projekt, in dem in einem weitflächigen Netz ein Wetterbeobachtungssystem über das Internet zugänglich sein soll. Dazu werden Java und TACOMA verwendet. Mole Das Mole-Projekt ist ein Forschungsprojekt des Fachbereichs an der Universität Stuttgart. Die Mobilen Agenten des Mole Systems sind ein Objektcluster ohne Referenzen zur Außenwelt und die mit den Benutzern oder anderen Agenten kommunizieren. Sie haben die Fähigkeit, ein Netzwerk von “Locations“ autonom zu durchwandern. Diese Locations abstrahieren real existierende Knoten im Netz. Die Agenten können Dienste anderer Agenten benutzen oder selbst Dienste zur Verfügung stellen. Das läßt sich gut mit dem Begriff “Software Robots“ beschreiben. Da die Agenten autonom von Location zu Location migrieren können, ist die Gewährleistung der Sicherheit des Computersystems als Basis dieser Abstraktionen von höchster Priorität. Agent-Tcl Am Dartmouth College in wurde das transportable Agentensystem Agent-Tcl entwickelt. Das Ziel dieses Systems ist, Applikationen zu unterstützen, die die Präsentation, Organisation und das Wiederauffinden von verteilten Informationen in “launenhaften“ Netzwerken benötigen. Die Hauptforschungsschwerpunkte dabei sind • Security Mechanismen • Unterstützung von mobilen und partiell verbundenen Rechnern • Tools zur Navigation und Entdeckung von Ressourcen • automatische Indexbildung, Cluster- und “Wiederfindungstechniken“ für Text und andere Dokumente • Formale Analyse von Agenten Aktionen gegenüber konkurrierenden Paradigmen. IBM Aglets Aglets Workbench ist eine visuelle Entwicklungsumgebung, um netzwerkbasierte Applikationen zu entwickeln, die mobile Agenten zum Finden von Informationen und Daten und auch den Zugriff auf diese nutzen. Diese Umgebung macht das Entwickeln von plattformunabhängigen Agenten, die in Java programmiert wurden, sehr einfach. Die Aglets Workbench Entwicklungsumgebung besteht aus den folgenden Elementen: • Aglets Framework Das java basierte Framework stellt alle agentenspezifischen Komponenten zur Verfügung: so z. B. ein globales, einheitliches Namensschema für Agenten, einen Classloader, um Agenten über das Netz zu laden, Mechanismen um Agenten zu verschicken und mit ande- ren Agenten zu kommunizieren etc. • Agent Transfer Protocol (ATP) Dieses Protokoll wird benutzt, um Agenten über das Netz zu transportieren. Es ist ein applikationen-level Standard Protokoll. • Visual Agent Manager Tahiti ist ein Agent Manager, der auf dem Aglets Framework basiert. Er benutzt eine GUI zur Kontrolle und Überwachung der Agenten. Ähnlich wie ein Web Browser ist Tahiti ein Desktop Tool für Agentennutzer. Die Sicherheit der Aglets wird durch ein erweitertes Security Layer Modell gewährleistet. Der erste Layer kommt von Java direkt, damit wird z. B. die Verifizierung des Bytecodes überprüft. Der nächste Layer ist der Security Layer, wo Aglet Framework Nutzer eigene Schutzmechanismen implementieren können. Der dritte Layer basiert auf der Java Security API, die digitale Signaturen, Verschlüsselungen etc. Unterstützt. 4. Ausblick Es wurde in dieser Arbeit aus Zeitgründen nur ein Teil eines mobilen Agentenscenarios verwirklicht, der Datenbankzugriff mittels Fernaufrufen von lokalen Agenten. Der nächste Schritt sollte die Mobilmachung des Agenten sein. Dafür soll der Agentencode vollständig über das Netz transportiert werden, um den Agenten mobil werden zu lassen. Da bei Objektserialisierung und Fernaufrufen die remoten Objekte nur per Referenz übergeben werden, muß ein geeigneter Classloader entwickelt werden, der unabhängig von diesen Mechanismen den Bytecode über das Netz laden kann. Dann müssen die zu übertragenden Daten gesichert werden durch digitale Signatur des Codes und der Verschlüsselung des public keys, da dieser unverschlüsselt kopiert werden könnte. Geeignet wäre die Übertragung der Daten über das Secure Socket Layer (SSL). In der nächsten Version jdk1.2 soll die Verbindung von RMI über SSL unterstützt werden. Der Agent soll dann von Server zu Server springen und aus den jeweiligen Datenbanken die gewünschten Informationen herausholen und gesammelt zum Client und damit zum Benutzer zurückbringen. Die geplante Architektur des endgültigen Agenten ist in Bild 4.1 dargestellt. Weiterführende Arbeiten in diese Richtung könnten sein, einen Agenten für den Zugriff auf andere Elemente wie z. B. einen Börsenkursserver zu entwickeln oder auch zum Einsatz in elektronischen Märkten und electronic commerce. Weiterhin muß die Kommunikation mit anderen Agenten zum Austausch von Daten und Informationen realisiert werden. Schließlich könnte der Agent intelligent und lernfähig gestaltet werden, um die Suche nach Informationen effizienter zu gestalten. Die Möglichkeiten dazu sind gegenwärtig noch Gegenstand der aktuellen Forschungen. Die Auswahl an bestehenden Projekten zeigt, daß nach der Verwirklichung der Agentenscenarios die Sicherheitsaspekte eine große Rolle spielen, egal welche Aufgaben die Agenten zu erfüllen haben. Das Entwickeln eines wirklich sicheren Agenten wird das vorrangige Ziel in der Agentenforschung sein. Es bleibt abzuwarten, wie sich die vorhandenen Sicherheitsmechanismen weiterentwickeln, da sich im Moment die globale Sicherheit eines Agenten und seiner Wirte schwer verwirklichen läßt. Bild 4.1 Geplante Architektur des Agentensystems Agent Agent Agent ServerA Client resultA resultA Agent resultA resultB result... Netz ServerB resultA resultB Agent Benutzeroberfläche resultA Agent Datenbank B Datenbank A Agent resultB resultA resultA resultB result... resultA resultB resultA resultB result... Agent Agent Server... resultA resultB result... Agent Agent Client resultA resultB Agent Datenbank ... result... Abkürzungsverzeichnis ACL API CORBA DB DBMS DLL HTTP ID IP JAR JDBC JVM KIF KQML MD5 RSA DSI ODBC QoS RDB RDBMS RMI RPC RSA RSA PKCS#1 SHA-1 SPI SQL SSL TAR Tcl TCP UDP URL VM WWW Agent Communication Language Applikation Programming Interface Common Object Request Broker Architecture DataBase DataBase Management System Dynamic Link Library HyperText Transfer Protocol Identity, Identifizierungsnummer in Beispieldatenbank Internet Protocol Java ARchive Java DataBase Connectivity Java Virtual Machine Knowlegde Interchange Format Knowledge Query and Manipulating Language Message Digest algorithm RSA-MD5, definiert durch in RFC 1321 Open DataBase Connectivity Quality of Service Relational DataBase Relational DataBase Management System Remote Method Invokation Remote Procedure Call Rivest, Shamir & Adleman AsymmetricCipher algorithm, Enkryption wie in RSA Laboratory Technical Note Secure Hash Algorithm, definiert in Secure Hash Standard, NIST FIPS 180-1 Service Provider Interface Structured Query Language Secure Socket Layer Tape ARchive Tool Command Language Transmission Control Protocol User Datagram Protocol Uniform Resource Loader Virtual Machine World Wide Web Literaturverzeichnis [ACCESS93] Microsoft-Corporation, "Microsoft Access, Relationale Datenbank für Windows, erste Schritte", Microsoft-Corporation, 1993. [ACL97] Sun-Microsystems, "Security in JDK1.1, Access Control List Abstractions", Javasoft, 1997, http://www.javasoft.com:80/products/jdk/1.1/docs/guide/security/Acl.html. [ARA97] Holger Peine, “Die Ara Plattform für mobile Agenten”, Universität Kaiserslautern, Fachbereich Informatik, AG Systemsoftware, 1997, http:www.uni-kl.de/AG-Nehmer/Ara/ara_D.html. [BLAS96] Blasberg, Andreas & Angela, "Datenbankentwicklung mit Access 95", AddisonWesley, veröffentl. im ECON Verlag, 1996. [BEPS97] Brian Epson, "JAVA Database Programming", John Wiley & Sons, Inc., 1997. [ERRE97] Helmut Erlenkötter, Volker Reher, "Java - HTML, Scripts, Applets und Anwendungen", Rowohlt Taschenbuch Verlag GmbH, 1997. [FRAGRA96] Stan Franklin & Art Graesser, "Is it an Agent, or just a Program? ", Institute for Intelligent Systems University of Memphis, Proceedings of the Third International Workshop on Agent Theories, Architectures and Languages, SpringerVerlag, 1996. [FUENF97] Stefan Fünfrocken, "Mobile Agenten", DAFID, TH-Darmstadt, Fachbereich Informatik, 1997, http://www.informatik.th-darmstadt.de/~fuenf/work/agenten/. [IBM96] Danny B. Lange & Daniel T. Chang, “IBM Aglets Workbench“, IBM Corporation, 1996, http://www.ibm.co.jp. [INTER97] Intersolv, "Developing Java und JDBC ," (White Paper), Intersolv, 2/97. [JAR97] Sun Microsystems, "JAR Guide", Sun Microsystems, Inc., 1996/1997, http://www.javasoft.com:80/products/jdk/1.1/docs/guide/jar/jarGuide.html. [JDBC97] Sun Microsystems, "JDBC™ Guide: Getting Started", Sun Microsystems, Inc., 1996/1997. [JKEY97] Sun Microsystems, "Using javakey", Sun Microsystems, Inc., 1996/1997, http://www.javasoft.com:80/security/usingJavakey.html. [KIF95] This document is a working draft for an American National Standard for KIF. It represents the consensus of the X3T2 Ad Hoc Group on KIF as of March 1995. [KQML97] http://www.cs.umbc.edu/kqml/. [MOLE97] Fritz Hohl, “MOLE: Overview”, Uni Stuttgart, Fachbereich Informatik, 1997, http://www.informatik.uni-stuttgart.de/ipvr/vs/projekte/mole/overview.html. [OBSER97] Sun Microsystems, "Java™ Object Serialization Specification ", Sun Microsystems, Inc., 1997. [RMI97a] Sun Microsystems, "Java™ RMI Tutorial ", Sun Microsystems, Inc., 1997. [RMI97b] Sun Microsystems, "Java™ Remote Method Invokation Specification ", Sun Microsystems, Inc., 1996/1997. [TCL97] http://www.sun.com./960710/cover/tcl.html, http://www.sun.com./960710/cover/tcl-safe.html.