From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+In diesem Abschnitt wird beschrieben, wie einem Applet der Zugriff
+auf geschützte Ressourcen gewährt werden kann. Wir gehen
+dazu in folgenden Schritten vor:
+
+Wir wollen uns die Aufgabe stellen, ein Applet zu schreiben, das einige
+Sicherheitsverstöße begeht. Zunächst soll es eine
+Datei auf dem lokalen Computer erzeugen und einen Zeitstempel hineinschreiben.
+Zusätzlich soll es auf einige geschützte System-Properties
+zugreifen und deren Inhalt in die Datei schreiben. Das Applet hat
+folgenden Aufbau:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 48 - Sicherheit und Kryptographie
+
+
+
+
+
+48.3 Signierte Applets
+
+
+
+
+
+
+
+
+
+
+48.3.1 Ein »unerlaubtes« Applet
+
+
+
+
+Listing 48.7: Ein »unerlaubtes« Applet
+
+
+
+
+
+001 /* TrustedApplet.java */
+002
+003 import java.awt.*;
+004 import java.applet.*;
+005 import java.util.*;
+006 import java.io.*;
+007
+008 public class TrustedApplet
+009 extends Applet
+010 {
+011 static final String ALLOWED_DIR = "c:\\tmp\\applets\\";
+012 static final String FNAME = "TrustedApplet.log";
+013 static final String LOGMSG = "Erzeugt von Applet: ";
+014 String msg;
+015
+016 public void init()
+017 {
+018 msg = "Uninitialisiert";
+019 FileWriter out = null;
+020 try {
+021 //Ausgabedatei erzeugen
+022 out = new FileWriter(ALLOWED_DIR + FNAME);
+023 //Logmessage schreiben
+024 out.write(LOGMSG);
+025 //Zeitstempel schreiben
+026 GregorianCalendar cal = new GregorianCalendar();
+027 out.write(cal.get(Calendar.DATE) + ".");
+028 out.write((cal.get(Calendar.MONTH) + 1) + ".");
+029 out.write(cal.get(Calendar.YEAR) + " ");
+030 out.write(cal.get(Calendar.HOUR_OF_DAY) + ":");
+031 out.write(cal.get(Calendar.MINUTE) + ":");
+032 out.write(cal.get(Calendar.SECOND) + "");
+033 out.write(System.getProperty("line.separator"));
+034 //System-Properties lesen und in Datei schreiben
+035 out.write(getProp("user.name"));
+036 out.write(getProp("user.home"));
+037 out.write(getProp("user.dir"));
+038 //Datei schließen
+039 msg = "Alle Sicherheitshuerden ueberwunden!";
+040 } catch (Exception e) {
+041 msg = e.toString();
+042 } finally {
+043 if (out != null) {
+044 try {
+045 out.close();
+046 } catch (IOException e) {
+047 //silently ignore
+048 }
+049 }
+050 }
+051 }
+052
+053 public void paint(Graphics g)
+054 {
+055 g.drawString(msg, 20, 20);
+056 }
+057
+058 private String getProp(String prop)
+059 {
+060 return prop + "=" +
+061 System.getProperty(prop) +
+062 System.getProperty("line.separator");
+063 }
+064 }
+
+
+TrustedApplet.java
+
+Es versucht zunächst eine Datei c:\tmp\applets\TrustedApplet.log +zu erzeugen. Wenn dies gelingt, instanziert es ein aktuelles GregorianCalendar-Objekt +und schreibt dessen Werte in die Datei. Schließlich versucht +es, die System-Properties »user.name«, »user.home« +und »user.dir« zu lesen und deren Werte ebenfalls in die +Datei zu schreiben. Sind all diese Versuche erfolgreich, gibt das +Applet die Meldung »Alle Sicherheitshuerden ueberwunden!« +aus. Tritt eine Ausnahme auf, wird deren Text ausgegeben. +
+
![]() |
+
+
+ +Um das Schreiben der Datei zu ermöglichen, ist ein Verzeichnis +c:\tmp\applets anzulegen. Andernfalls +gibt es eine IOException +- selbst wenn alle Sicherheitshürden genommen sind. |
+
+
|
+![]() |
+
+Das Applet kann mit folgender HTML-Datei gestartet werden: + + +
+
+
++001 <html> +002 <head> +003 <title>TrustedApplet Demo</title> +004 </head> +005 +006 <body> +007 <h1>TrustedApplet Demo</h1> +008 +009 <applet +010 code="TrustedApplet.class" +011 width=600 +012 height=200 +013 > +014 TrustedApplet Demo +015 </applet> +016 +017 </body> +018 </html>+ + |
+
+Das Applet kann nun beispielsweise mit dem appletviewer
+gestartet werden:
+
+
+appletviewer TrustedApplet.html
+
+
+
+
+Wird es ohne weitere Vorkehrungen gestartet, scheitert es bereits +am Erzeugen der Ausgabedatei und gibt eine SecurityException +auf dem Bildschirm aus. + + + + +
+Zum Signieren ist es zunächst erforderlich, alle für den
+Betrieb des Applets nötigen Dateien in ein jar-File zu packen.
+Signiert wird also nicht eine einzelne .class-Datei,
+sondern alle Dateien innerhalb des jar-Archivs. Dazu verwenden wir
+folgendes Kommando:
+
+
+jar cvf trapp.jar TrustedApplet.class
+
+
+
+
+Jetzt wird ein jar-Archiv trapp.jar erstellt, +das die Klassendatei TrustedApplet.class +enthält. Dieses Archiv muss nun signiert werden. Dazu steht im +JDK das Hilfsprogramm jarsigner +zur Verfügung. Es arbeitet kommandozeilenbasiert und wird folgendermaßen +aufgerufen: +
+
+
++jarsigner -signedjar outjar injar alias ++ + |
+
+Die einzelnen Elemente haben folgende Bedeutung: +
+Nachdem wir in Abschnitt 48.1.6
+bereits ein Schlüsselpaar mit dem Alias »hjp3« erzeugt
+und in der Schlüsseldatenbank abgelegt haben, muss der Aufruf
+von jarsigner
+so erfolgen:
+
+
+C:\--->jarsigner -signedjar strapp.jar trapp.jar hjp3
+Enter Passphrase for keystore: hjp3ks
+Enter key password for hjp3: hjp3key
+
+
+
+
+Die beiden Paßwörter zum Zugriff auf die Schlüsseldatenbank +und den Schlüssel werden auf Nachfrage in der Kommandozeile angegeben. +Nachdem das Programm einige Zeit gerechnet hat, erzeugt es das signierte +Archiv mit dem Namen strapp.jar. +
+
![]() |
+
+
+ +jarsigner +bietet neben den hier erwähnten noch weitere Optionen, auf die +wir nicht weiter eingehen wollen. Das Programm wird zusammen mit den +anderen Hilfsprogrammen in der Tool-Dokumentation des JDK ausführlich +beschrieben. |
+
+
|
+![]() |
+
+Bisher wurde das Applet direkt aus der .class-Datei +geladen. Um es aus einem jar-Archiv zu laden, muss das APPLET-Tag +der HTML-Datei um das archive-Argument +erweitert werden: + + +
+
+
++001 <-- TrustedApplet.html --> +002 +003 <html> +004 <head> +005 <title>TrustedApplet Demo</title> +006 </head> +007 +008 <body> +009 <h1>TrustedApplet Demo</h1> +010 +011 <applet +012 archive="strapp.jar" +013 code="TrustedApplet.class" +014 width=600 +015 height=200 +016 > +017 TrustedApplet Demo +018 </applet> +019 +020 </body> +021 </html>+ + |
++TrustedApplet.html | +
+
![]() |
+
+
+ +Wir könnten das Applet jetzt wie zuvor starten, würden aber +immer noch dieselbe SecurityException +erhalten. Es ist zwar signiert und das Zertifikat ist auf diesem Rechner +bekannt (denn hier wurde es erstellt). Die Policy-Datei ist aber noch +nicht angepasst, und daher lehnt der SecurityManager +des JDK die Ausführung der gefährlichen Operationen nach +wie vor ab. |
+
+
|
+![]() |
+
+Soll das signierte Applet auf anderen Arbeitsplätzen laufen, +ist es erforderlich, das Zertifikat des Schlüssels, mit dem es +signiert wurde, dort zu installieren. Soll es dagegen nur auf dem +Arbeitsplatz laufen, auf dem auch der Schlüssel generiert wurde, +ist das nicht erforderlich. Bei der Generierung des Schlüssels +wurde ja auch ein (selbstsigniertes) Zertifikat erzeugt. + +
+Um das Zertifikat weitergeben zu können, muss es zunächst
+unter Verwendung der Option -export
+von keytool
+aus der lokalen Schlüsseldatenbank exportiert werden:
+
+
+keytool -export -alias hjp3 -file hjp3.cert
+
+
+
+
+Es liegt nun in der Datei hjp3.cert und
+kann auf das Zielsystem kopiert werden. Mit der -import-Option
+von keytool
+kann es dort in die Schlüsseldatenbank aufgenommen werden:
+
+
+C:\--->keytool -import -alias hjp3 -file hjp3.cert
+Enter keystore password: hjp3ks
+Owner: CN=Guido Krueger, O=Computer Books, C=de
+Issuer: CN=Guido Krueger, O=Computer Books, C=de
+Serial number: 38663e2d
+Valid from: Sun Dec 26 17:11:25 GMT+01:00 1999 until: Sat Mar 25 17:11:25 GMT+01
+:00 2000
+Certificate fingerprints:
+ MD5: D5:73:AB:06:25:16:7F:36:27:DF:CF:9D:C9:DE:AD:35
+ SHA1: E0:A4:39:65:60:06:48:61:82:5E:8C:47:8A:2B:04:A4:6D:43:56:05
+Trust this certificate? [no]: y
+Certificate was added to keystore
+
+
+
+
+Nach dem Aufruf muss zunächst das Paßwort der Schlüsseldatenbank +angegeben werden. Dann zeigt das Programm die Eigenschaften des Zertifikats +an und erwartet, dass die Informationen bestätigt werden. Anschließend +wird das Zertifikat in die Schlüsseldatenbank aufgenommen. + + + + +
+Der letzte Schritt besteht darin, die Sicherheitseinstellungen auf +dem Zielsystem anzupassen. Applets, die mit dem Zertifikat verifiziert +werden können, das unter dem Alias »hjp3« in der Schlüsseldatenbank +abgelegt wurde, sollen Dateien im Verzeichnis c:\tmp\applets +lesen und schreiben und auf die System-Properties »user.name«, +»user.home« und »user.dir« zugreifen können. + +
+Die Sicherheitseinstellungen des JDK werden mit Hilfe von Policy-Dateien +definiert. Es gibt zwei Stellen im Dateisystem, von denen das JDK +sie standardmäßig einliest: +
+
![]() |
+![]() |
+
+
+ +Policy-Dateien können auch an beliebigen anderen Stellen im Dateisystem +liegen. In diesem Fall muss beim Aufruf des Java-Interpreters das +System-Property »java.security.policy« mit dem Namen der +zu verwendenen Policy-Datei angegeben werden. Wäre beispielsweise +hjp3policy die zu verwendende Policy-Datei, +so müsste der Appletviewer mit der Option »-J-Djava.security.policy=hjp3policy« +aufgerufen werden. |
+
+
|
+![]() |
+
+Policy-Dateien sind zeilenorientierte Textdateien, die mit einem gewöhnlichen +Texteditor bearbeitet werden können. Alternativ stellt das JDK +ein einfaches GUI-basiertes Hilfsprogramm mit dem Namen policytool +zur Verfügung, mit dem Policy-Dateien erstellt und bearbeitet +werden können. Auf seine Verwendung wollen wir aber nicht weiter +eingehen. + +
+Eine Policy-Datei enthält zwei Arten von Einträgen. Beide +sind optional: +
+Alle Einträge werden mit einem Semikolon beendet. Kommentare +können an beliebiger Stelle durch // oder /* ... */ angelegt +werden. + +
+Der »keystore«-Eintrag erwartet als Argument einen URL,
+der auf die Schlüsseldatenbank verweist. Auf einem Windows-98-Einzelplatzsystem
+sieht er beispielsweise so aus:
+
+
+keystore "file:/c:/windows/.keystore";
+
+
+
+
+Die »grant«-Einträge haben folgende Syntax: +
+
+
+
+grant [SignedBy "signer"] [, CodeBase "URL"] {
+ permission permission_class [ "target" ] [, "action"]
+ [, SignedBy "signers"];
+ ...
+};
+
+
+ |
+
+Eine Berechtigung kann wahlweise an einen Unterzeichner oder eine +Ladeadresse (oder beide) vergeben werden. Die Option »SignedBy« +führt eine Liste von Aliasnamen auf, deren Zertifikate vorhanden +sein müssen, damit die Berechtigung gewährt wird. Die Option +»CodeBase« spezifiziert die Adresse, von der ein Applet +geladen werden darf, um die Berechtigung zu halten. Fehlt die CodeBase-Klausel, +wird nur die Unterzeichnerliste verwendet; fehlt die SignedBy-Klausel, +ist es nur die Ladeadresse. + +
+Nach einer öffnenden geschweiften Klammer folgen beliebig viele +Berechtigungen, die jeweils durch das Schlüsselwort »permission« +eingeleitet werden. Anschließend wird der Eintrag mit einer +schließenden geschweiften Klammer abgeschlossen. Der zuvor spezifizierte +Berechtigte erhält alle Berechtigungen, die zwischen den beiden +Klammern angegeben sind. + +
+Jede Berechtigung muss als erstes Argument den Namen einer Berechtigungsklasse +angeben. Daneben kann sie zwei weitere Argumente target und +action haben, mit denen Details spezifiziert werden. Tabelle 48.1 +listet die gebräuchlichsten Berechtigungen und ihre Argumente +auf. Details können (und müssen) in dem Dokument »Java +Security Architecture« nachgelesen werden, das Bestandteil der +JDK-Dokumentation ist. + +
+
| Klasse | +Zugriff auf | +Target | +Action |
| java.io.FilePermission | +Dateien und Verzeichnisse | +Datei- oder Verzeichnisnamen. Wird als letztes +Zeichen ein »*« angegeben, so gilt die Berechtigung für +das komplette Verzeichnis. Steht dort ein »-«, so gilt sie +zusätzlich für alle Unterverzeichnisse. Wird »<<ALL +FILES>>« angegeben, gilt die Berechtigung für alle +Dateien in allen Verzeichnissen! | +read, write, delete, execute |
| java.net.SocketPermission | +TCP/IP-Verbindungen | +Hostname oder IP-Adresse, gefolgt von Portnummern-Bereich | +accept, connect, listen, resolve |
| java.util.PropertyPermission | +System-Properties | +Names des Properties | +read, write |
| java.lang.RuntimePermission | +Die Klasse Runtime | +exitVM, stopThread, loadLibrary, queuePrintJob, +... | +- |
| java.awt.AWTPermission | +Window-Ressourcen | +accessClipboard, showWindowWithoutWarningBanner, +... | +- |
| java.security.AllPermission | +Alle Ressourcen | +- | +- |
+Tabelle 48.1: Wichtige Permission-Klassen
+ + + + +
+Nach diesen Vorbemerkungen können wir die Policy-Datei \windows\.java.policy
+erstellen. Sie hat folgenden Inhalt:
+
+
+keystore "file:/c:/windows/.keystore";
+
+grant SignedBy "hjp3" {
+ permission java.io.FilePermission "c:\\tmp\\applets\\*", "read,write";
+
+ permission java.util.PropertyPermission "user.name", "read";
+ permission java.util.PropertyPermission "user.home", "read";
+ permission java.util.PropertyPermission "user.dir", "read";
+};
+
+
+
+
+Im ersten Eintrag geben wir die Position der Schlüsseldatenbank +an, sie liegt im Verzeichnis c:\windows. +Anschließend definieren wir die Berechtigungen für alle +Applets, die mit dem Zertifikat »hjp3« signiert wurden. +Zunächst erhalten sie Schreib- und Leseberechtigung im Verzeichnis +c:\tmp\applets. Dort können sie +ohne weitere Einschränkungen Dateien anlegen, überschreiben +und lesen. Zusätzlich erlauben wir den so signierten Applets, +die drei System-Properties »user.name«, »user.home« +und »user.dir« zu lesen. + +
+Nun läßt sich unser signiertes Applet ohne SecurityException
+aufrufen und gibt die erlösende Meldung »Alle Sicherheitshuerden
+ueberwunden« aus. Im Verzeichnis c:\tmp\applets
+sollte sich anschließend eine Datei TrustedApplet.log
+befinden und etwa folgenden Inhalt haben:
+
+
+Erzeugt von Applet: 30.12.1999 20:50:40
+user.name=Guido Krüger
+user.home=C:\WINDOWS
+user.dir=C:\arc\doku\hjp3\misc
+
+
+
+
+
+
+
+Die Prüfung der Zugriffsberechtigungen wird mit Hilfe der Klasse +SecurityManager +aus dem Paket java.lang +vorgenommen. Der SecurityManager +ist ein Objekt, das entweder gar nicht oder genau einmal im laufenden +Java-Programm vorhanden ist. Nach der ersten Instanzierung kann es +nicht mehr geändert oder entfernt werden. + +
+Zugriffe auf den SecurityManager
+sind an den Stellen der Laufzeitbibliothek eingebaut, an denen auf
+gefährliche Ressourcen zugegriffen wird. Ein Beispiel aus der
+Klasse FileInputStream
+sieht etwa so aus:
+
+
+...
+SecurityManager security = System.getSecurityManager();
+if (security != null) {
+ security.checkRead(name);
+}
+//Gefährlicher Code
+...
+
+
+
+
+Zunächst wird geprüft, ob ein SecurityManager +installiert wurde. Ist das nicht der Fall, fährt das Programm +ohne Einschränkung fort. Gibt es dagegen einen SecurityManager, +wird dessen checkRead-Methode +aufgerufen. Sie löst eine SecurityException +aus, wenn die gewünschte Berechtigung fehlt. Der Code hinter +dem checkRead +wird in diesem Fall nicht mehr erreicht. Ist die Berechtigung dagegen +vorhanden, wird checkRead +ohne weitere Aktionen beendet und der dahinter liegende Code ausgeführt. + +
+Applets besitzen grundsätzlich einen SecurityManager.
+Der AppletViewer bzw. Web-Browser sorgen während der Initialisierung
+für dessen Instanzierung. Applikationen dagegen haben normalerweise
+keinen SecurityManager
+(das ist der Grund, weshalb in Applikationen alle gefährlichen
+Operationen erlaubt sind). Soll eine Applikation einen SecurityManager
+erhalten, so kann sie entweder mit der Option »-Djava.security.manager«
+gestartet werden, oder der SecurityManager
+kann im Programm selbst installiert werden:
+
+
+...
+System.setSecurityManager(new SecurityManager());
+...
+
+
+
+
+Das folgende Beispielprogramm gibt den Inhalt des System-Properties +»user.name« aus. Normalerweise kann es ohne Fehler ausgeführt +werden: + + +
+
+
+
+001 /* SecuMgrTest.java */
+002
+003 public class SecuMgrTest
+004 {
+005 public static void main(String[] args)
+006 {
+007 System.out.println(
+008 "user.name is " + System.getProperty("user.name")
+009 );
+010 }
+011 }
+
+ |
++SecuMgrTest.java | +
+Läuft es dagegen unter Kontrolle eines SecurityManagers, so führt
+der Aufruf zu einer SecurityException:
+
+
+C:\--->java -Djava.security.manager SecuMgrTest
+Exception in thread "main"
+ java.security.AccessControlException: access denied
+ (java.util.PropertyPermission user.name read)
+ at java.security.AccessControlContext.checkPermission(
+ AccessControlContext.java:276)
+ at java.security.AccessController.checkPermission(
+ AccessController.java:403)
+ at java.lang.SecurityManager.checkPermission(
+ SecurityManager.java:549)
+ at java.lang.SecurityManager.checkPropertyAccess(
+ SecurityManager.java:1242)
+ at java.lang.System.getProperty(System.java:555)
+ at Test1.main(SecuMgrTest.java:7)
+
+
+
+
+Bei Bedarf kann man Applikationen auf diese Weise mit denselben Sicherheitsmechanismen +ausstatten wie Applets. jar-Dateien, aus denen Applikationen geladen +werden, lassen sich ebenso signieren wie solche, aus denen Applets +geladen werden. Die in der Policy-Datei definierten Rechte gelten +dann für die daraus gestartete Applikation. +
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |