6.3 Zugriffsschutz in Java Zusätzlich zum Schutz durch das Betriebssystem gewünschter Zugriff gemäß Politik und Klasse erlaubter Zugriff JVM BS gemäß Benutzer-Privilegien und Schutzstatus erlaubter Zugriff Die Java Sicherheitspolitik gilt zusätzlich zu den Sicherheitsmechanismen des Betriebssystems auf dem Java läuft. Eine Java-Anwendung mit großzügiger Sicherheitspolitik kann versuchen, die Passwortdatei zu lesen, aber wenn der Benutzer, welcher die Anwendung laufen lässt, die Berechtigung zum Lesen der Passwort-Datei nicht besitzt, wird die Java-Anwendung nicht die Datei lesen können. Die globale Zugriffsschutzstrategie ist der Schnitt der Strategie für die Java-Anwendung und der Strategie des Betriebssystems. 1 6.3 Zugriffsschutz in Java Java-Spracheigenschaften erhöhen Sicherheit • keine Pointer-Arithmetik, daher keine ungültigen Speicherzugriffe • Automatisches Speichermanagement • Garbage Collection • automatisches Prüfen von Arraylängen • strenge Typisierung, daher keine illegalen Casts • Zugriffsrechte, Einschränkung der Sichtbarkeit von Elementen • Klassen, Variablen und Methoden können als final deklariert werden, daher keine weiter Ableitung der Klasse, Verändern von Variablenwerten oder Überschreiben von Methoden • Execeptions ermöglichen definierte und kontrollierte Programmabbrüche Java wurde mit dem Ziel entwickelt, einfach nutzbar zu sein. Die Hoffnung war, dass dies die Fehler von Programmieren verglichen mit anderen Programmiersprachen wie C oder C++ minimiert und somit die Sicherheit der Programme erhöht wird. Die Sicherheit in Java wird durch einige Eigenschaften erhöht: Java besitzt, anders als C oder C++, keine Pointer, so dass keine ungültigen Speicherzugriffe möglich sind. Java besitzt ein automatisches Speichermanagement, Garbage Collection, ein automatisches Prüfen von String- und Arraylängen, betrachtet Zugriffsrechte und schränkt die Sichtbarkeit auf Elementen ein. Außerdem können in Java Klassen, Variablen und Methoden als final deklariert werden, womit eine weitere Ableitung der Klasse, das Verändern von Variablenwerten und das Überschreiben von Methoden nicht mehr möglich ist. Exceptions ermöglichen definierte und kontrollierte Programmabbrüche. 2 6.3 Zugriffsschutz in Java Sichtbarkeit private: nur Code der Klasse default (package): Code der Klasse oder selbes Paket protected: Code der Klasse, selbes Paket oder Subklasse public: von jeder anderen Klasse Beurteilung: schützt Code vor Code statisch, ohne dynamische Prüfungen unterstützt least-priveledge-Prinzip fördert Programmsicherheit Jede Entität eines Java-Programms hat ein Zugriffsschutzlevel: private: Die Entität kann nur von Code innerhalb der Klasse aufgerufen werden, in der die Entität definiert ist. default (or package): Die Entität kann von Code aufgerufen werden, der innerhalb der Klasse der Entität definiert ist oder von einer Klasse, die im Paket der Entität enthalten ist. protected: Die Entität kann nur von Code aufgerufen werden, welcher in der Klasse der Entität enthalten ist, von Klassen desselben Pakets oder von einer Subklasse. public: Auf die Entität kann von jeder anderen Klasse aus zugegriffen werden. 3 6.3 Zugriffsschutz in Java Sicherheitsmechanismen der JVM Class File Verifier Stellt sicher, das nur berechtigter Java Bytecode ausgeführt wird. Überprüfung erfolgt in vier Schritten: 1. Format für Java-Klassen wird geprüft. 2. Integrität der Klasse wird geprüft (z.B. dass die Klasse von einer nicht finalen Klasse abgeleitet ist) 3. Bytecode Verifier: Bytcode wird nach unzulässigen Instruktionen überprüft, z.B. richtige Anzahl und Typen von Parametern, Variablen sind initialisiert etc. 4. Überprüfung von Verweisen auf Klassen sowie auf Methoden und Attribute anderer Klassen (z.B. ob referenzierte Methode überhaupt existiert) Die Virtuelle Maschine verbirgt Besonderheiten und Gefahren der ausführenden Architektur und überwacht Programmausführung und Rechte. Der Java Compiler und der Class File Verifier stellen sicher, dass nur berechtigter Java Bytecode ausgeführt wird. Die Überprüfung der Binärdaten erfolgt in vier Schritten, von denen im ersten die Einhaltung des im Sprachstandard vorgegebenen Formats für Java-Klassen sichergestellt wird. Die Struktur beinhaltet u. a. Informationen zur Version der Klasse, übergeordneten Klassen, Methoden und Attributen. Im zweiten Schritt wird die Integrität der Klasse geprüft, z.B. ob das Untersuchungsobjekt von einer gültigen, nicht finalen Superklasse abgeleitet wurde. Ist die Klasse vom Typ Object, so gilt diese Einschränkung nicht. Im dritten Schritt folgt der Aufruf des Bytecode Verifiers, dem wohl wichtigsten, aber auch komplexesten Bestandteil des Class File Verifiers. Er überprüft den Bytecode vor dessen Ausführung nochmals auf unzulässige Instruktionen. Dazu zählt der Gebrauch der Parameter, die in richtiger Anzahl und korrektem Datentyp einem Aufruf folgen müssen. In Schritt 4 werden alle Verweise auf andere Klassen sowie auf Methoden und Attribute anderer Klassen verfolgt und überprüft. 4 6.3 Zugriffsschutz in Java Class Loader definiert lokalen Namensraum, der gefährlichen Code von der Beeinflussung korrekten und sicheren Codes abhält. Jeder Class Loader hat einen eigenen Namensraum (verhindert das Laden mehrerer Klassen mit demselben Namen). Namensräume sind „Schutzschild“ zwischen Klassen unterschiedlicher Namensräume: Innerhalb eines Namensraums können Klassen kommunizieren (z.B. über public-Methoden). Klassen in unterschiedlichen Namespaces (von unterschiedlichen Class Loadern) können nicht direkt kommunizieren. Der Klassenlader (class loader) definiert einen lokalen Namensraum (namespace), welcher dazu benutzt werden kann, gefährlichen Code von der Beeinflussung korrekten und sicheren Codes abzuhalten. Ein Namespace ist eine Menge unabhängiger und eindeutiger Namen (ein Name pro geladener Klasse). Jeder Class Loader besitzt solch einen eigenen Namespace. Falls z.B. eine Klasse Auto in einen Namespace geladen wird, ist es danach unmöglich eine weitere Klasse mit dem Namen Auto in diesen Namespace zu laden. Es ist jedoch möglich mehrere Auto-Klassen in eine Virtual Machine zu laden, solange sich diese in unterschiedlichen Namespaces befinden (von unterschiedlichen Class Loadern geladen werden). Namespaces legen eine Art Schutzschild zwischen Klassen unterschiedlicher Namespaces: Klassen in identischen Namespaces können über die gewohnten Möglichkeiten miteinander kommunizieren, z.B. über mit dem Schlüsselwort public definierte Methoden. Sobald sich zwei Klassen aber in unterschiedlichen Namespaces befinden, also von unterschiedlichen Class Loadern geladen wurden, ist es für diese nicht einmal möglich, die Existenz der jeweils anderen festzustellen, solange der Programmierer dies nicht explizit ermöglicht. 5 6.3 Zugriffsschutz in Java Class Loader bilden eine Hierarchie (seit JDK1.2). Bootstrap Class Loader ist verantwortlich für das Laden der Core-Klassen der JAVA API. Werden als trusted angesehen. Benutzerdefinierte Class Loader laden restliche Klassen (z.B. der ausgeführten Applikation) Bootsrap Class Loader Class Loader N Class Loader 1 Seit Java Version 1.2 bilden die Class Loader eine Hierarchie. Die Class Loader wurden in einer VaterSohn Beziehung angeordnet. Der sogenannte Bootstrap Class Loader steht dabei in der Hierarchie an der Spitze. Dieser Class Loader ist nur für das Laden der Klassen der Core-Java API zuständig. Für das Laden anderer Klassen, wie z.B. die Klassen der ausgeführten Applikation, sind seit Version 1.2 benutzerdefinierte Class Loader verantwortlich. 6 6.3 Zugriffsschutz in Java Vorgang beim Laden einer Klasse: • Class Loader 1 möchte Klasse K laden. • Class Loader 1 fragt Class Loader 2, ob er K laden kann. • ... • Class Loader N fragt Bootstrap Class Loader, ob er Klasse K laden kann. • Wenn der Bootstrap Class Loader die Klasse K hat, so wird sie zum Class Loader 1 hindurchgereicht. • Wenn der Bootstrap Class Loader die Klasse K nicht hat, so versucht der Class Loader N die Klasse zu laden. • .... Bootsrap Class Loader Class Loader N Class Loader 1 Möchte eine Applikation eine Klasse laden, so gibt der erste Class Loader die Anfrage an seinen Vaterknoten weiter, der selbst die Anfrage wieder an seinen Vaterknoten weiterleitet. Der letzte Knoten in der Hierarchie ist der Bootstrap Class Loader. Dieser sucht die zu ladende Klasse in der Java API. Findet er die Klasse nicht, so gibt er die Anfrage wieder an seinen Sohn Class Loader weiter, der ebenfalls versucht die Klasse zu laden usw. Kann der Bootstrap Class Loader jedoch die Klasse laden, so gibt er die Klasse an seine Sohnknoten weiter, die dann ihrerseits nicht mehr versuchen die Klasse zu laden. 7 6.3 Zugriffsschutz in Java Ladevorgang verhindert, dass man trusted-Klassen (z.B. java.lang.String) durch eigene Klassen überschreibt. Anderes Beispiel: Angreifer schreibt java.lang.Virus. Anfrage zum Laden von java.lang.Virus gelangt zunächst zum Bootstrap Class Loader, der zwar das Paket java.lang, aber die Klasse nicht findet. Alle anderen Class Loader der Hierarchie finden die Klasse auch nicht, so dass java.lang.Virus vom Class Loader des Angreifers geladen wird. Frage: Kann java.lang.Virus nun auf die Klassen (z.B. protected) im Paket java.lang zugreifen? Nein, da die Pakete java.lang von verschiedenen Class Loadern geladen wurden (und somit in verschiedenen runtime packages sind). Der Class Loader verhindert das Verändern von trusted class libraries. Trusted class libraries sind die Pakete, die von der Java Virtual Machine als definitiv sicher angesehen werden. Dazu gehören die Klassen der Core Java API. Wenn ein benutzerdefinierter Class Loader beispielsweise versuchen würde, eine eigenen java.lang.String Klasse zu laden, würde diese Anfrage als erstes bis zum Bootstrap Class Loader nach oben geleitet. Dieser würde feststellen, dass das Paket java.lang zur Java API gehört und die Referenz auf diese Klasse zurückgeben. Betrachten wir ein zweites Beispiel. Angenommen ein Programm möchte die Datei java.lang.Virus laden, die die Virtual Machine angreifen soll. Analog zum ersten Beispiel würde auch diese Anfrage bis ganz nach oben delegiert werden, der Bootstrap CL würde feststellen, dass er zwar das Paket java.lang kennt, aber die Klasse nicht enthalten ist und würde zurückgeben, dass er die Klasse nicht laden kann. Da auch alle anderen übergeordneten Class Loader die Datei nicht in ihrem Bereich finden können, würde sie also, wie vom Angreifer gewünscht, von dem eigenen Class Loader geladen. Da diese im Paket java.lang liegt könnte man jetzt davon ausgehen, dass diese die gleichen Rechte hat, wie jede Klasse in diesem Paket, beispielsweise auf mit dem Schlüsselwort protected geschützte Methoden und Attribute zuzugreifen. Dies ist aber nicht möglich, da die java.lang API Pakete von einem anderen Class Loader geladen wurden, als die java.lang.Virus Klasse. Hier kommt der Begriff des runtime packages ins Spiel, der bedeutet, dass sich zwei (oder mehrere) Klassen nur dann im gleichen runtime package befinden, wenn sie den gleichen Paketnamen haben und sie vom gleichen Class Loader geladen wurden. Da sich, um auf packagesichtbare Variablen und Methoden zugreifen zu können, die beiden Klassen im gleichen runtime package befinden müssen ist es der hier beispielhaft beschriebenen java.lang.Virus Klasse also nicht möglich, die java.lang Klassen der API zu beeinflussen. 8 6.3 Zugriffsschutz in Java Security Manager (und Access Controler in Java 2) Zugriffe auf Ressourcen werden vom Security Manager der JVM geprüft, z.B. - Netzwerkzugriffe alle Operationen zum Manipulieren von und der Zugriff auf Threads der Zugriff auf Systemressourcen Zugriffe auf das Dateisystem das Aufrufen von lokalen Programmen und Betriebssystem-Kommandos Der Zugriff zu sicherheitskritischen Ressourcen läuft über die Java Virtual Machine und wird vorher durch den Security Manager geprüft. Der Security Manager schränkt die Aktionen von nicht vertrauenswürdigem Code auf ein Minimum ein. Die Operationen, die als gefährlich eingeschätzt werden und deshalb mit dem Security Manager kontrolliert werden können, sind beispielsweise: · Netzwerkzugriffe · alle Operationen zum Manipulieren von und der Zugriff auf Threads · der Zugriff auf Systemressourcen · Zugriffe auf das Dateisystem · das Aufrufen von lokalen Programmen und Betriebssystem-Kommandos 9 6.3 Zugriffsschutz in Java Definiert check-Methoden, die kritische Aktionen überwachen: z.B. checkRead(String file), checkAccess(Thread t) , checkDelete(Sting file) Vor JDK 1.2 war java.lang.SecurityManager eine abstrakte Klasse. Benutzer mussten eigenen Security Manager schreiben und von der Klasse java.lang.SecurityManager ableiten. Der Sicherheits-Manager ist ein Objekt, das für jede kritische Operation eine Methode zur Verfügung stellt, welche für die entsprechende Operation überprüft, ob sie ausgeführt werden darf oder nicht. Beispielsweise wird die Methode public void checkDelete(String file) des Security Managers von der Java API immer aufgerufen, bevor eine Datei gelöscht wird. Diese Methode muss überprüfen, ob die als Parameter angegebene Datei gelöscht werden darf und wenn dies nicht der Fall ist, eine Exception erzeugen, so dass die Operation abgebrochen wird. Vor JDK Version 1.2. war die Klasse java.lang.SecurityManager eine abstrakte Klasse. Um benutzerdefinierte Sicherheitsrichtlinien zu installieren musste man seinen eigenen Security Manager schreiben und von der Klasse java.lang.SecurityManager ableiten. Sobald eine Applikation dann den Security Manager instantiiert und installiert kümmert sich der Security Manager um die Einhaltung der Sicherheitsrichtlinien, die durch die check-Methoden definiert wurden. 10 FileInputStream fis = new FileInputStream("Textdatei.txt"); Erzeugen des FileInputStream Objects -> Security Manager muss um Erlaubnis gefragt werden Ist ein Security Manager installiert NO Recht wird gewährt YES checkRead() wird aufgerufen Lesen erlaubt? NO checkRead() throws Exception YES checkRead() returns read wird ausgeführt Dieses Diagramm zeigt an einem Beispiel die bei der Ausführung einer sicherheitskritischen Operation nötigen Schritte. Wenn keine Security Manager installiert ist, wird der Zugriff sofort gewährt. Gibt es einen Security Manager, wird die entsprechende check()-Methode des installierten Security Managers aufgerufen und der Zugriff von diesem überprüft. 11 6.3 Zugriffsschutz in Java Seit JDK 1.2 ist java.lang.SecurityManager eine konkrete Klasse, die eine Default-Implementierung des Security Managers darstellt. Installieren des default Security Managers über die Kommandozeile mittels -Djava.security.manager Eine benutzerdefinierte Sicherheitsrichtlinie wird, anstatt in Java-Code, in einem ASCII-File (policy file) definiert. Seit Java 1.2 ist die Klasse java.lang.SecurityManager eine konkrete Klasse, die eine DefaultImplementierung des Security Managers darstellt. Der Default Security Manager kann durch Aufruf folgender Option über die Kommandozeile installiert werden: -Djava.security.manager. Benutzerdefinierte Sicherheitspolitiken werden in einem ASCII-File, genannt Policy File, definiert und nicht mehr in Java-Code implementiert (d.h. in der abgeleiteten Klasse des abstrakten SecurityManagers) . 12 6.3 Zugriffsschutz in Java Zugriff auf Systemressourcen läuft weiterhin über Security Manager, dieser implementiert aber nicht mehr die Zugriffsregeln. Security Manager reicht Anfrage an den Access Controller weiter. Access Controler verwendet das Poilcy File zur Zugriffsentscheidung. Beim Zugriff auf Systemressourcen wird in Java 2 zwar weiterhin der Security Manager konsultiert, die Zugriffsregeln allerdings sind nicht mehr in ihm implementiert, sondern werden an den Access Controller weitergeleitet. Wenn also eine check-Methode des default Security Managers aufgerufen wird, so wird der Request an die Klasse AccessControler weitergeleitet. Der Access Controller verwendet die Information des Policy Files, um zu entscheiden, ob die Aktion erlaubt werden soll oder nicht. 13 6.3 Zugriffsschutz in Java Sandboxmodell JDK 1.0 Sandbox ist eine beschränkte Umgebung für nicht vertrauenswürdigen Code Lokaler Code ist vertrauenswürdig und hat vollen Zugriff auf Systemressourcen. Code aus dem Internet (Applet) ist nicht vertrauenswürdig. Security Manager bestimmt die erlaubten Zugriffe. Das originale Java Sicherheitsmodell, bekannt als „Sandbox" Modell, stellt eine sehr beschränkte Umgebung zur Verfügung, in der nicht vertrauenswürdiger Code ausgeführt werden kann. Im Sandbox-Modell ist lokaler Code vertrauenswürdig und hat vollen Zugriff zu den Systemressourcen, wie das Dateisystem. Code, der aus dem Internet geladen wurde (Applet) ist nicht vertrauenswürdig und kann nur auf die beschränkten Ressourcen in der Sandbox zugreifen. Der Security Manager ist verantwortlich, zu bestimmen, welche Ressourcenzugriffe erlaubt sind. 14 6.3 Zugriffsschutz in Java In der Sandbox sind folgende Aktionen nicht möglich. • Lesen oder Schreiben auf der lokalen Platte • Eine Netzwerkverbindung zu einem Rechner aufbauen außer dem Rechner, von dem das Applet geladen wurde. • Einen neuen Prozess starten • Eine neue DLL laden Aktionen, die Code in der Sandbox nicht möglich sind, zeigt die Folie. 15 6.3 Zugriffsschutz in Java Sandboxmodell JDK 1.1 Signierung von Applets Digital signierte Applets werden wie lokaler Code behandelt. Öffentlicher Schlüssel zum Verifizieren muss vertrauenswürdig sein. Unsignierte Applets laufen weiterhin in der Sandbox JDK 1.1 führte „signierte Applets„ ein. Ein digital signiertes Applet wird wie lokaler Code behandelt, mit vollen Zugriff auf die Ressourcen, wenn der öffentliche Schlüssel zum Verifizieren der Signatur vertrauenswürdig ist. Unsignierte Applets werden weiterhin in der Sanbox ausgeführt. Signierte Applets werden mit ihrer Signatur in signierten JAR (Java ARchive) Dateien geliefert. 16 6.3 Zugriffsschutz in Java Sandboxmodell JDK 1.2 Code wird mit einer Sicherheitspolitik assoziert. Sicherheitspolitik enthält eine Menge von Permissions (z.B. Erlaubnis zum Zugriff auf Systemressource oder Verbindung zu einem Rechner bzw. Port). Sicherheitspolitik wird vom Benutzer oder Administrator definiert. JDK 1.2 führt mehrere Erweiterungen bzgl. JDK 1.1. ein: Erstens, der gesamte Code, egal ob local oder remote, kann nun mit einer Sicherheitspolitik (security policy) assoziiert werden. Die Sicherheitspolitik definiert eine Menge von Permissions und muss bei einem Benutzer oder dem Systemadministrator konfiguriert werden. Jede Permission spezifiziert einen erlaubten Zugriff auf eine bestimmte Ressource, z.B. Lese- und Schreibzugriff auf eine Datei oder ein Verzeichnis oder die Erlaubnis sich zu einem bestimmten Host oder Port zu verbinden. 17 6.3 Zugriffsschutz in Java Sandboxmodell JDK 1.2 Code ist in Domänen (domains) aufgeteilt. Domäne ist eine Menge von Klassen, deren Instanzen die gleichen Rechte haben. Extreme von Domänen: voller Zugriff und Sandbox-Konfiguration. Die Laufzeitumgebung organisiert den Code in Domänen (domains), jede betrifft eine Menge von Klassen, deren Instanzen die gleichen Rechte gewährleistet werden. Eine Domäne kann wie eine Sandbox konfiguriert sein, so dass Applets weiterhin in einer beschränkten Umgebung ausgeführt werden können. Der linke Pfeil in der Abbildung entspricht einer Domäne, in der dem Code vollen Zugriff gewährt wird. Der Pfeil auf der rechten Seite repräsentiert das andere Extrem. Diese Domäne entspricht der Sandbox. Die dazwischen liegenden Domänen haben weniger Zugriffsrechte als der volle Zugriff aber mehr als die Sandbox. 18 6.3 Zugriffsschutz in Java Wenn Klassen durch einen Class Loader in die JVM geladen werden, wird jeder Klasse genau eine Domäne zugeordnet. Threads, die mehrere Domänen umfassen, haben den Schnitt der Permissions dieser Domänen. a.class b.class c.class d.class Dom A Permissions Dom B Permissions Klasse Domain Permission Eine Domäne umfasst eine Menge von Klassen, deren Instanzen dieselbe Menge von Permissions haben. Die Java Anwendungsumgebung verwaltet eine Abbildung vom Code (Klassen und Instanzen) zu ihren Domänen und dann zu ihren Permissions. Threads können komplett in einer Domäne ablaufen oder können mehrere Domänen umfassen. In diesem Fall gilt, dass die Menge der Permissions für den Thread der Schnitt der Permissions aller Domänen ist, die der Thread benutzt. 19 6.3 Zugriffsschutz in Java Permissions repräsentieren den Zugriff auf Systemressourcen. Abstrakte Klasse java.security.Permission Neue Permissions erweitern diese Klasse. Actions sind die erlaubten Aktionen auf einem Objekt, z.B. perm1 = new FilePermission(p1,"read,write"); perm2 = new FilePermission(p2,"write,read"); Die Permission-Klassen repräsentieren den Zugriff zu Systemressourcen. Die java.security.Permission Klasse ist eine abstrakte Klasse, von der Unterklassen für bestimmte Zugriffe abgeleitet werden können. Ein Beispiel einer solchen Permission zum Lesen einer Datei „abc“ im Verzeichnis /tmp zeigt der folgende Code: perm = new java.io.FilePermission("/tmp/abc", "read"). Neue Permissions können von der Permission-Klasse oder Unterklassen abgeleitet werden. Die abstrakte Methode implies muss von neuen Permission-Klassen implementiert werden. Grob gesehen, bedeutet „a implies b“, dass jemandem, dem die Permission A gewährt wird, auch die Permission b gewährt wird. Die meisten Permissions enthalten eine Liste von „Actions“ die sagt, welche Aktionen für das Objekt erlaubt sind. In einem java.io.FilePermission Objekt könnte die Aktionsliste beispielsweise aus „read, write“ bestehen. 20 6.3 Zugriffsschutz in Java Beipsiel: java.io.FilePermission Aktionen sind read, write, delete und execute import java.io.FilePermission; FilePermission FilePermission FilePermission FilePermission FilePermission FilePermission FilePermission FilePermission p p p p p p p p = = = = = = = = new new new new new new new new FilePermission("myfile", "read,write"); FilePermission("/home/gong/", "read"); FilePermission("/tmp/mytmp", "read,delete"); FilePermission("/bin/*", "execute"); FilePermission("*", "read"); FilePermission("/-", "read,execute"); FilePermission("-", "read,execute"); FilePermission("<<ALL FILES>>", "read"); Ein Beispiel einer speziellen Permission ist die java.io.FilePermission. Diese gibt die Erlaubnis für den Zugriff auf eine Datei oder ein Verzeichnis (spezifiziert im Parameter path). Die Aktionen für den Parameter actions sind read, write, delete, und execute. Die Folie zeigt einige Beispiele ihrer Anwendung. Das Beispiel FilePermission p = new FilePermission("/home/gong/", "read"); gibt beispielsweise die Permission zum Lesen des Verzeichnisses (d.h. das Auflisten der darin enthaltenen Dateien), jedoch nicht das Leserecht auf den Dateien selbst. Um auch die Dateien des Verzeichnisses lesen zu können, muss man dies explizit durch den Dateinamen angeben oder durch „*“ (alle Dateien im Verzeichnis) bzw. „-“ (alle Dateien im Verzeichnis und allen Unterverzeichnissen). Mit <<ALL FILES>> wird die Permission auf allen Dateien des Systems gewährt. 21 6.3 Zugriffsschutz in Java Beispiel: java.lang.RuntimePermission Permission braucht nicht unbedingt keine Aktionen. createClassLoader setContextClassLoader createSecurityManager modifyThread modifyThreadGroup readFileDescriptor getClassLoader setSecurityManager exitVM stopThread getProtectionDomain writeFileDescriptor ... Die java.lang.RUntimePermission ist ein Beispiel einer Permission, die keine Aktionen erfordert. Das Zielobjekt der RuntimePermission kann als String repräsentiert werden ohne das eine Aktion mit diesem Zielobjekt verbunden wäre. RuntimePermission("exitVM") soezifiziert zum Beispiel die Permission die Java Virtual Machine zu verlassen. 22 6.3 Zugriffsschutz in Java Die implies-Methode vereinfacht den Vergleich von Permissions und gibt einen Überblick über die Mächtigkeit einer Permission. Beispiel: java.io.FilePermission("/tmp/*", "read") impliziert java.io.FilePermission("/tmp/a.txt", "read") Um Permissions besser miteinander vergleichen zu können, muss jede Permission die implies-Methode implementieren. Betrachten wir zum Beispiel java.io.FilePermission("/tmp/*", "read"), so impliziert diese Permission java.io.FilePermission("/tmp/a.txt", "read"). 23 6.3 Zugriffsschutz in Java Implikation ist nicht immer offensichtlich. Wenn Applet die Permission zum Schreiben auf dem Dateisystem hat, kann es die JVM Runtime-Umgebung austauschen, in der es dann alle Permissions hat. Wenn ein Applet die RuntimePermission zum Erzeugen von Class Loadern hat, hat es auch viele Permissions des Class Loaders. Gefahren der Permissions sind unter http://java.sun.com/j2se/1.4.2/docs/guide/security/permissions.html# PermRisks beschrieben. Nicht bei allen Permissions ist diese Implikation jedoch für den Programmierer so offensichtlich. Nehmen wir ein Applet an, welches die Permission write zum Schreiben auf dem gesamten Dateisystem hat. Dies erlaubt dem Applet u.a. die JVM Runtime-Umgebung zu ersetzen. Damit hat dann das Applet alle Permissions. Ein anderes Beispiel ist ein Applet, welcher die Runtime Permission gewährt wird, um Class Loader zu erzeugen. Damit werden dem Applet auch viele Permissions des Class Loaders gewährt. Andere „gefährliche“ Permissions und ihre Risiken sind unter http://java.sun.com/j2se/1.4.2/docs/guide/security/permissions.html#PermRisks beschrieben. 24 6.3 Zugriffsschutz in Java java.lang.Runtime Permission Was erlaubt die Permission Risiko createClassLoader Erzeugt einen Class Loader Anwendungen können ihren eigenen Class Loader erzeugen, mit dem sie ihre eigenen Klassen ins System laden. Diese Klassen können in jede Domäne gepackt werden, womit den Klassen die Domänen-Permissions gewährt werden. getClassLoader Dies erlaubt einem Angreifer den Class Loader einer Klasse zu erhalten. Jedoch können auch alle anderen Klassen geladen werden, auf die der Angreifer keinen Zugriff hat. Erhalten eines Class Loaders Diese und die nächste Folie zeigen ein Beispiel für die Risiken, die sich durch die Zuordnung der RuntimePermission ergeben können. 25 6.3 Zugriffsschutz in Java java.lang.RuntimeP Was erlaubt ermission die Permission Risiko setSecurityManager Setzt einen Security Manager Dies erlaubt Code den Securiyt Manager gegen einen weniger restriktiven Security Manager auszutauschen, um die Zugriffüberprüfungen des ursprünglichen Security Managers zu umgehen. exitVM Erlaubt Denial-of-Service-Attacken Anhalten der JVM ..und viele weitere Gefahren ! 26 6.3 Zugriffsschutz in Java Policy-Objekt repräsentiert die Politik einer Java Anwendung. Politik ist in einer oder mehreren Politik-Konfigurationsdateien spezifiziert. Beispiel eines Politik-Konfigurationseintrages: grant codeBase "file:/home/sysadmin/" { permission java.io.FilePermission "/tmp/abc", "read"; }; Die Sicherheitspolitik für eine Java Anwendung wird durch ein Policy-Objekt repräsentiert. Damit ein Applet (oder eine Anwendung, die unter einem Security Manager läuft) geschützte Aktionen (wie das Lesen oder Schreiben von Dateien) durchführen kann, müssen ihm die Permissions für diese Aktion gewährt werden. Eine Ausnahme ist, das Code immer das Recht hat, Dateien von seiner CodeSource zu lesen. Es werden in diesem Fall keine Permissions benötigt. Es kann mehrere Instanzen des PolicyObjekts geben, aber immer nur eine ist zu einem Zeitpunkt für die Zugriffsschutzentscheidung relevant. Die Politik kann in einem oder mehreren Politik-Konfigurationsdateien spezifiziert werden. Die PolitikDateien spezifizieren welche Permission für welchen Code stammend von welcher Quelle erlaubt sind. Ein Beispieleintrag in einer Politik-Datei zeigt die Folie, bei der Code vom Verzeichnis /home/sysadmin die Erlaubnis zum Lesen des Verzeichnisses /tmp/abc gegeben wird. 27 6.3 Zugriffsschutz in Java Politik-Dateien können im Textedtior oder mit dem Tool policytool erstellt werden. Systemweite Standard-Politik unter java.home\lib\security\java.policy (Windows) (Optionale) Benutzerspezifische Politik unter user.home\.java.policy (Windows) Politik-Objekt wird mit Systempolitik initialisiert und die benutzerspezifische wird (fals vorhanden) hinzugefügt. Eine Politik-Datei kann in einem Texteditor geschrieben werden oder mittels dem Policy Tool (Kommando polictyTool) erstellt werden. Es gibt eine systemweite Standard Politik-Datei in java.home/lib/security/java.policy (Solaris) bzw. java.home\lib\security\java.policy (Windows) und eine optionale benutzerspezifische Politik-Datei unter user.home/.java.policy (Solaris) bzw. user.home\.java.policy (Windows). Wenn das Politik-Objekt initialisiert wird, wird zunächst die systemweite Politik geladen und dann die benutzerspezifische zugefügt. 28 6.3 Zugriffsschutz in Java Policy-Datei-Format enthält einen Keystore-Eintrag und eine Liste von „grant“-Einträgen. Keystore ist Datenbank für private Schlüssel mit Zertifikaten für die öffentlichen Schlüssel (siehe Kryptographie 3.6.5.1) Keystore benutzt öffentliche Schlüssel der in den „grant“-Einträgen angegebenen Signierenden. Syntax: keystore "some_keystore_url", "keystore_type"; keystore_type gibt das Speicher- und Datenformat des Keystores an. Eine Policy-Konfigurationsdatei kann einen „keystore“-Eintrag und null oder mehr „grant“-Einträge enthalten. Ein Keystore ist eine Datenbank privater Schlüssel mit entsprechenden X.509 Zertifikaten für die zugehörigen öffentlichen Schlüssel. Der Keystore wird dazu benutzt, die öffentlichen Schlüssel derjenigen zu ermitteln, die in den „grant“-Einträgen als Signierende angeben sind. Der KeystoreEintrag hat die folgende Syntax: keystore "some_keystore_url", "keystore_type"; Hierbei spezifiziert "some_keystore_url" die URL des Keystores und "keystore_type" spezifiziert (optional) den Keystoretyp. Ein Keystortyp definiert das Speicher- und Datenformat der KeystoreInformationen und die Algorithmen zum Schutz der Schlüssel. 29 6.3 Zugriffsschutz in Java Ein „grant“-Eintrag gibt eine Menge von Permissions an spezifizierten Code. Beispiele: Permission a.b.Foo für Code signiert von Roland: grant signedBy "Roland" { permission a.b.Foo; }; FilePermission für jeden Code (unabhängig vom Signierenden oder der codeBase): grant { permission java.io.FilePermission ".tmp", "read"; }; Jeder „grant“-Eintrag besteht aus einem CodeSource und den gewährten Permissions. Die folgenden Folien zeigen einige Beispiele. 30 6.3 Zugriffsschutz in Java Zwei Permissions für Code signiert von Li und Roland: grant signedBy "Roland,Li" { permission java.io.FilePermission "/tmp/*", "read"; permission java.util.PropertyPermission "user.*"; }; Zwei Permissions für Code signiert von Li und der Code stammt von http://java.sun.com: grant codeBase "http://java.sun.com/*",signedBy "Li" { permission java.io.FilePermission "/tmp/*", "read"; permission java.io.SocketPermission "*", "connect"; }; 31 6.3 Zugriffsschutz in Java Zwei Permissions für Code signiert von Li und Roland, nur wenn der Bytecode für com.abc.TVPermission von Li signiert ist. grant signedBy "Roland,Li" { permission java.io.FilePermission "/tmp/*","read"; permission com.abc.TVPermission "channel-5", "watch", signedBy "Li"; }; 32 6.3 Zugriffsschutz in Java Access Controller überprüft bei einem Zugriff, ob die erforderlichen Permissions existieren. Geschieht mittels Stack Inspection. Java Runtime Bytecode Identity Code Source Signers Policy Access Controller " Stack Inspection Die Überprüfung auf ausreichende Rechte wird seit JDK1.2 von der Klasse AccessController bewerkstelligt. Dabei werden Maßnahmen ergriffen, um Missbrauch von Code mit mehr Rechten durch ein Programm mit wenigen Rechten zu verhindern. Dies geschieht durch Überprüfung aller Rufer am Call Stack. Dieser Mechanismus wird als Stack Inspection bezeichnet. 33 6.3 Zugriffsschutz in Java Stack Inspection Überprüft ob alle Aufrufer in der Ruferkette die entsprechenden Permissions haben. Class A Domain 1 Class B Domain 2 Class C Domain 3 java.io.file Domain 4 Systemressource Access Controller prüft ob die Permission vorhanden ist. Stack Inspection Bei einer Stack Inspection wird geprüft, ob alle Methoden in der Ruferkette die entsprechenden Permissions besitzen. Nur wenn alle Rufer am Call Stack die entsprechende Permission besitzen, darf eine Aktion ausgeführt werden. Betrachten wir als Beispiel eine Klasse A, die eine Methode der Klasse B aufruft, die wiederum eine Methode der Klasse C aufruft, welche schließlich eine Methode der Klasse java.io.file aufruft. Die Klasse java.io.file veranlasst durch den Aufruf der Methode checkPermission( Permission perm) den Access Controller zur Überprüfung der Rechte. Der Access Controller für alle Klassen überprüfen, ob sie ausreichende Permissions zum Aufrufen der jeweiligen Methoden haben. Reichen die Permissions für eine Klasse nicht aus, so wird der Zugriff verwehrt. 34 6.3 Zugriffsschutz in Java Access Controller überprüft der Reihe nach, ob die Aufrufer auf dem Stack die geforderte Permission haben. Überprüft die Permission mit der Methode implies() des ProtectionDomain-Objekts. public boolean implies(Permission permission) Hat einer der Aufrufer nicht die benötigte Permission, so gibt der Access Controller eine AccessControlException zurück und der Zugriff auf die Systemressource wird nicht ausgeführt. Der AccessController überprüft der Reihe nach alle Rufer am Stack auf die geforderte Permission, indem er die Methode implies(Permission p) aufruft. Die Methode implies() ist in der Klasse ProtectionDomain deklariert. Als einzigen Parameter erwartet diese Methode ein Objekt vom Typ Permission. Diese Methode überprüft ob eine Permission in der ProtectionDomain enthalten ist. Ist das der Fall wird true zurückgegeben, andernfalls false. Stellt der AccessController während der Stack Inspection fest, dass einer der Rufer nicht über die geforderte Permission verfügt, wird die weitere Überprüfung mit der Erzeugung einer AccessControlException abgebrochen und der Zugriff auf die Ressource kann nicht ausgeführt werden. Die Operation bricht ihrerseits mit einer SecurityException ab. 35 6.3 Zugriffsschutz in Java Java 2 SDK, v. 1.4 bietet zusätzlich zur Java Sicherheitsarchitektur: Java Crytography Extension (JCE) Enthält z.B. Pakete für Verschlüsselung (symmetrisch, asymmetrsich, Block- und Strom), Schlüsselgenerierung, Message Authentication Code Java Authentication and Authorization Service (JAAS) Enthält Pakte zur Authentifizierung und Zugriffskontrolle von Benutzern. Java Secure Socket Extension (JSSE) Enthält Pakte für sichere Internet-Kommunikation (z.B. SSL, TLS). Neben dem Standard Sicherheitsaspekte: Java Sicherheitsmodell, gibt es Ergänzungen für weitere -Die Java Cryptography Extension (JCE) ist eine Menge von Paketen für Verschlüsselung, Schlüsselgenerierung und Message Authentication Code (MAC) Algorithmen. Verschlüsselung beinhaltet symmetrische, asymmetrische, Block- und Stromverschlüsselung. -Der Java Authentication and Authorization Service (JAAS) ist eine Menge von Paketen zur Authentifizierung und Zugriffskontrolle von Benutzern. -Die Java Secure Socket Extension (JSSE) ist eine Menge von Paketen die eine sichere Internet-Kommunikation ermöglichen. Implementiert eine Java Version von Secure Sockets Layer (SSL) und Transport Layer Security (TLS) Protokollen. Enthält Funktionen für die Datenverschlüsselung, Server-Authentifizierung, Nachrichtenintegrität und optional ClientAuthentifizierung. 36 6.3 Zugriffsschutz in Java JAAS ist eine Ergänzung zur Java 2 SDK Sicherheitsarchitektur Die Java 2 SDK Sicherheitsarchitektur ist Code-zentriert, d.h. die Zugriffsentscheidung basiert auf der Frage: Woher kommt der Code und wer hat ihn signiert? JAAS ist Benutert-basiert, d.h. die Zugriffsentscheidung basiert auf der Frage: Wer führt den Code aus? JAAS Autorisierung erweitert die Java Sicherheitsarchitekur. Die Java Sicherheitsarchitektur benutzt eine Security policy, um zu spezifizieren, welche Zugriffsrechte einem Code zugewiesen werden. Diese Architektur ist Code-zentriert, d.h. die Permissions wurden basierend auf den Eigenschaften des Codes erteilt: woher kommt der Code und wer hat ihn signiert. Mit der Integration von JAAS in das Java 2 SDK ist es nun möglich benutzerbasierte Permissions zu definieren. Somit basiert der Zugriffsschutz nun nicht nur auf dem Code der ausgeführt wird, sondern auch darauf, wer den Code ausführt. 37 6.3 Zugriffsschutz in Java Java 2 Sicherheit ist Code-zentriert CodeSource Code Signierende Permissions Das Java Standardsicherheitsmodell ist Code-zentriert. In der Security Policy werden Permissions aufgrund der Herkunft des Codes und des Signierenden des Codes vergeben. 38 6.3 Zugriffsschutz in Java Java 2 und JAAS CodeSource Code Signierende Benutzer Permissions Mit JAAS kann in der Security Policy auch spezifiziert werden, an welchem Benutzer die Permission gebunden ist. 39 6.3 Zugriffsschutz in Java JAAS Authentifizierung Weist einem Benutzer, der eine Anwendung ausführt, eine authentifizierte Benutzererkennung (Principal) zu. Anwendungen sind unabhängig vom Authentifizierungsservice Anwendung LoginContext LoginModule Kerberos Smartcard Modulkonfiguration Biometrie Das Prinzip von JAAS ist, dass dem Benutzer, der die Anwendung ausführt (in der JAAS-Terminologie »Subject« genannt) eine oder mehrere authentifizierte Benutzerkennungen (als »Principals« bezeichnet) zugeordnet werden. Die JAAS Architektur erlaubt Anwendungen unabhängig vom Authentifizierungsservice zu bleiben. Es kann beispielsweise eine Authentifizierung über Kerberos, Smartcards, Biometrie etc. erfolgen. Die Schnittstelle zwischen JAAS und einem Programm, das JAAS benutzt, ist die Klasse LoginContext aus dem Paket javax.security.auth.login. 40 6.3 Zugriffsschutz in Java LoginContext beschreibt den Namen des Kontextes, der die LoginModulkonfiguration spezifiziert (Modulkonfiguration steht in einer Datei). einen CallbackHandler, der Benutzerinteraktionen für das Modul durchführt (z.B. Abfrage eines Passworts) Da Benutzer-Abfragen mit der Anwendung variieren, sind sie nicht direkt im Modul kodiert, sondern getrennt im CallbackHandler. Ein LoginContext benötigt zwei Informationen: 1. Den Namen des Kontextes. Dieser Name identifiziert die Login-Modulkonfiguration, die für den Kontext verwendet werden soll. Diese Modulkonfiguration steht in einer Datei. 2. Ein Exemplar der Klasse CallbackHandler. Dieses Objekt dient dazu, Benutzerinteraktionen durchzuführen, die die Module benötigen. Eine solche Interaktion könnte die Abfrage eines Passworts sein. Da die Form solcher Abfragen stark von der Anwendung abhängt (z. B. Kommandozeile oder grafischer Dialog), sind sie nicht in den Modulen selbst kodiert, sondern werden über einen CallbackHandler abgewickelt. 41 6.3 Zugriffsschutz in Java Verwendung von JAAS erfordert 1. Erstellen einer Konfigurationsdatei, in der das Authentifizierungsmodell eingetragen wird. 2. Erstellen eines CallbackHandlers, der die Benutzerinteraktion durchführt. 3. Erzeugen eines LoginContext, mit dessen Methode login() das Login durchgeführt werden kann. Für die Verwendung von JAAS sind daher drei Schritte durchzuführen: 1. Es ist eine Konfigurationsdatei zu erstellen, in der das gewünschte Authentifizierungsmodul eingetragen wird. 2. Es muss eine Unterklasse von CallbackHandler erstellt werden, in der die Benutzerinteraktion durchgeführt wird. 3. Es muss ein LoginContext erzeugt werden, mit dessen Methode login() das eigentliche Login durchgeführt werden kann. 42 6.3 Zugriffsschutz in Java Beispiel: Modulkonfiguration Demo Demo { com.sun.security.auth.module.UnixLoginModule required debug=false; }; J2SE Standard-Login-Modul für Unix, das die UNIX Benutzer-ID, unter der die Anwendung läuft, zur Benutzererkennung (Principal) verwendet. Benötigt keine Benutzerinteraktion (und damit keinen CallbackHandler), da direkt die Betriebssystem-Benutzererkennung benutzt wird. Das Modul com.sun.security.auth.module.UnixLoginModule ist ein Login-Modul, das standardmäßig bei J2SE dabei ist und Principals für Unix-Benutzer-IDs ausstellt, unter der das Programm ausgeführt wird. Dieses Modul erfordert keine Benutzerinteraktion und somit auch keinen speziellen CallbackHandler. Die Principals werden automatisch aus der Betriebssystem-Benutzerkennung erstellt. 43 6.3 Zugriffsschutz in Java Weitere Standard-Module sind JndiLoginModule für eine Authentifizierung gegenüber einem LDAP-Verzeichnis. Krb5LoginModule für die Anmeldung an einem Kerberos-System. KeyStoreLoginModule für eine Authentifizierung gegenüber einem Java Key Store. Neben den beiden genannten Modulen werden standardmäßig z.B. noch folgende Module mitgeliefert: Das JndiLoginModule für eine Authentifizierung gegenüber einem LDAP-Verzeichnis. Das Krb5LoginModule für die Anmeldung an einem Kerberos-System. Das KeyStoreLoginModule für eine Authentifizierung gegenüber einem Java Key Store. 44 6.3 Zugriffsschutz in Java Login-Kontext für die Konfiguration "Demo" erzeugen try { loginContext = new LoginContext("Demo"); // mit CallbackHandler // loginContext = new LoginContext("Demo„, // CallbackHandler); } catch (LoginException e) {} Durchführung des Logins loginContext.login(); 45 6.3 Zugriffsschutz in Java JAAS erlaubt mehrere Login-Module in einer Konfiguration Demo { com.sun.security.auth.module.UnixLoginModu le required debug=false; demo.MyLoginModule optional debug=false; }; Tags in Konfiguration entscheiden, wie sich die gesamte Authentifizierung bzgl. Der Modul-Authentifizierungen verhält. Bei JAAS können Login-Module auch kaskadiert, d. h. nacheinander ausgeführt werden. Im Beispiel der Folie wird zunächst eine Anmeldung mit dem UnixLoginModule und danach mit MyLoginModule durchgeführt. Die Authentifizierung erfolgt dann in zwei Phasen: In der ersten Phase werden die LoginInformationen für alle Module ermittelt. Erst wenn alle Module diese erste Phase erfolgreich durchlaufen haben, beginnt die zweite Phase, in der dem Benutzer die Principals hinzugefügt werden. Daher wird bei JAAS zwischen dem Ergebnis eines einzelnen Moduls und dem Ergebnis der gesamten Kette unterschieden. Bei JAAS kann für jedes einzelne Login-Modul konfiguriert werden, ob die Principals nur dann gewährt werden, wenn die gesamte Kette erfolgreich war, oder ob es bereits genügt, wenn das Modul selbst abgeschlossen wurde. 46 6.3 Zugriffsschutz in Java Tags für die Modulkonfiguration legen fest, ob Modul Erfolg für den Erfolg der Gesamtanmeldung haben muss, nachfolgende Module zur Ausführung kommen Tag Erfolg zwingend Ausführung folgender Module required ja immer requisite ja nur bei Erfolg sufficient nein nur bei Misserfolg optional nein immer Die einzelnen Tags in der Modellkonfiguration legen fest, ob das betreffende Modul Erfolg haben muss, damit die Gesamtanmeldung noch als erfolgreich gilt. Es kann auch definiert werden, ob nachfolgende Module überhaupt noch zur Ausführung kommen sollen. Die Tags sind im Einzelnen: required Die Authentifizierung des Moduls muss erfolgreich sein, damit die Gesamtauthentifizierung erfolgreich ist. Nachgeordnete Login-Module werden in jedem Fall noch ausgeführt, unabhängig davon, ob die Anmeldung mit diesem Modul fehlschlägt. requisite Die Authentifizierung des Moduls muss erfolgreich sein, damit die Gesamtauthentifizierung erfolgreich ist. Falls die Anmeldung mit diesem Modul fehlschlägt, ist auch die Gesamtauthentifizierung fehlgeschlagen und login() kehrt sofort zurück. Ist die Anmeldung mit diesem Modul dagegen erfolgreich, werden nachgeordnete Login-Module auch noch ausgeführt. sufficient Die Authentifizierung mit dem Modul braucht nicht zwingend erfolgreich sein, damit die Gesamtauthentifizierung erfolgreich ist. Ist sie erfolgreich, gilt die Gesamtauthentifizierung als erfolgreich und login() kehrt sofort zurück. Schlägt die Anmeldung mit diesem Modul fehl, werden nachgeordnete Login-Module auch noch ausgeführt. optional Die Authentifizierung mit dem Modul braucht nicht zwingend erfolgreich sein, damit die Gesamtauthentifizierung erfolgreich ist. Nachgeordnete Login-Module werden in jedem Fall noch ausgeführt, unabhängig davon, ob die Anmeldung mit diesem Modul fehlschlägt. 47 6.3 Zugriffsschutz in Java JAAS Autorisierung Basiert auf den bei der Authentifizierung zugewiesenen Principals. Beispiele: Permission zum Lesen und Schreiben des Verzeichnisses "/home/Alice„ für Code der als X500Principal mit "Alice„ ausgeführt wird. grant principal javax.security.auth.x500.X500Principal "Alice" { permission java.io.FilePermission "/home/Alice", "read, write"; }; Nachdem sich ein Benutzer authentifiziert hat, bietet JAAS Zugriffsschutz basierend auf den bei der Authentifizierung zugewiesenen Principals des Benutzers. In JAAS kann in der Politik-Datei spezifiziert werden, auf welche Ressourcen welche Principals zugreifen können. Im Beispiel darf der Code im Verzeichnis /home/Alice lesen und schreiben, wenn der Code von einem Principal der Klasse javax.security.auth.x500.X500Principal ausgeführt wird und die getName()-Methode „Alice“ zurückgibt. 48 6.3 Zugriffsschutz in Java Permission zum Lesen und Schreiben in "/tmp/games" für Code von "www.games.com", signiert von "Duke" und ausgeführt von "Alice„. grant codebase "http://www.games.com", signedBy "Duke", principal javax.security.auth.x500.X500Principal "Alice" { permission java.io.FilePermission "/tmp/games", "read, write"; }; Kombination aus Code-basiertem und Benutzer-basiertem Zugriffsschutz. Ein zweites Beispiel zeigt diese Folie. 49 6.3 Zugriffsschutz in Java Durchsetzen der JAAS-Politik LoginModule Principal Principal Principal Subjekt Authentifizierung Subjekt Aktion SecurityManager Politik Autorisierung Zunächst erfolgt eine Authentifizierung, d. h. ein Subjekt wird durch den Login-Prozess mit Principals versehen. Der Security Manager prüft dann anhand der Principals des Subjektes und der Politik, ob das Subjekt eine spezifische Aktion durchführen darf. 50 6.3 Zugriffsschutz in Java Aktion als bestimmtes Subjekt ausführen mit doAs()Methode der Klasse Subject. public static Object doAs( final Subject subject, final java.security.PrivilegedAction action) Security Manager (bzw. Access Controller) prüft, ob die Politik die Berechtigungen für die Aktion für einen der Principals des Subjekts gibt. Sollen Aktionen unter einem bestimmten Subjekt ausgeführt werden, gibt es die Methode doAs() der Klasse Subject. Der SecurityManager prüft dann, ob die Policy die benötigten Berechtigungen für einen der Principals des Subjects gibt. 51 6.3 Zugriffsschutz in Java Beispiel: Benutzer hat sich vorher authentifiziert. Subject subject = loginContext.getSubject(); try { subject.doAs(subject,new ExampleAction()); } catch(PrivilegedActionException e) {...} mit class ExampleAction implements java.security.PrivilegedAction { } 52