6.3 Zugriffsschutz in Java

Werbung
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
Herunterladen