Sicherheit und die Class Loader-Architektur

Zurück 1 2 Page 2 Seite 2 von 2

Klassenlader und Namensräume

Für jede geladene Klasse verfolgt die JVM, welcher Klassenlader - ob primordial oder objekt - die Klasse geladen hat. Wenn eine geladene Klasse zum ersten Mal auf eine andere Klasse verweist, fordert die virtuelle Maschine die referenzierte Klasse von demselben Klassenladeprogramm an, das die referenzierende Klasse ursprünglich geladen hat. Wenn die virtuelle Maschine beispielsweise eine Klasse Volcanoüber einen bestimmten Klassenlader lädt , versucht sie, alle Klassen zu laden, Volcanoauf die über denselben Klassenlader verwiesen wird. Wenn Volcanoauf eine Klasse mit dem Namen Lavaverwiesen wird, z. B. durch Aufrufen einer Methode in der Klasse Lava, fordert die virtuelle Maschine Lavaden geladenen Klassenlader an Volcano. Die vom LavaKlassenladeprogramm zurückgegebene Klasse ist dynamisch mit der Klasse verknüpft Volcano.

Da die JVM diesen Ansatz zum Laden von Klassen verwendet, können Klassen standardmäßig nur andere Klassen sehen, die von demselben Klassenladeprogramm geladen wurden. Auf diese Weise können Sie mit der Java-Architektur mehrere Namensräume in einer einzigen Java-Anwendung erstellen. Ein Namensraum ist eine Reihe eindeutiger Namen der Klassen, die von einem bestimmten Klassenladeprogramm geladen werden. Für jeden Klassenlader verwaltet die JVM einen Namensraum, der mit den Namen aller Klassen gefüllt ist, die über diesen Klassenlader geladen wurden.

Wenn eine JVM beispielsweise eine Klasse mit Namen Volcanoin einen bestimmten Namensraum geladen hat , ist es unmöglich, eine andere Klasse mit Namen Volcanoin denselben Namensraum zu laden . Sie können jedoch mehrere VolcanoKlassen in eine JVM laden , da Sie in einer Java-Anwendung mehrere Namensräume erstellen können. Sie können dies einfach tun, indem Sie mehrere Klassenlader erstellen. Wenn Sie in einer laufenden Java-Anwendung drei separate Namensräume (einen für jeden der drei Klassenlader) erstellen, Volcanokann Ihr Programm durch Laden einer Klasse in jeden Namensraum drei verschiedene VolcanoKlassen in Ihre Anwendung laden .

Eine Java-Anwendung kann mehrere Klassenladeobjekte entweder aus derselben Klasse oder aus mehreren Klassen instanziieren. Es kann daher so viele (und so viele verschiedene Arten von) Klassenladeobjekten erstellen, wie es benötigt. Klassen, die von verschiedenen Klassenladeprogrammen geladen werden, befinden sich in unterschiedlichen Namensräumen und können nur dann aufeinander zugreifen, wenn die Anwendung dies ausdrücklich zulässt. Wenn Sie eine Java-Anwendung schreiben, können Sie Klassen, die aus verschiedenen Quellen geladen wurden, in verschiedene Namensräume trennen. Auf diese Weise können Sie die Class Loader-Architektur von Java verwenden, um die Interaktion zwischen Code zu steuern, der aus verschiedenen Quellen geladen wurde. Sie können verhindern, dass feindlicher Code auf benutzerfreundlichen Code zugreift und diesen unterwandert.

Klassenlader für Applets

Ein Beispiel für eine dynamische Erweiterung mit Klassenladeprogrammen ist der Webbrowser, der Klassenladeobjekte verwendet, um die Klassendateien für ein Applet über ein Netzwerk herunterzuladen. Ein Webbrowser löst eine Java-Anwendung aus, die ein Klassenladeobjekt installiert - normalerweise als Applet-Klassenladeprogramm bezeichnet -, das weiß, wie Klassendateien von einem HTTP-Server angefordert werden. Applets sind ein Beispiel für eine dynamische Erweiterung, da die Java-Anwendung beim Start nicht weiß, welche Klassendateien der Browser zum Herunterladen über das Netzwerk auffordert. Die herunterzuladenden Klassendateien werden zur Laufzeit festgelegt, da der Browser auf Seiten stößt, die Java-Applets enthalten.

Die vom Webbrowser gestartete Java-Anwendung erstellt normalerweise für jeden Speicherort im Netzwerk, von dem Klassendateien abgerufen werden, ein anderes Applet-Klassenladeobjekt. Infolgedessen werden Klassendateien aus verschiedenen Quellen von verschiedenen Klassenladeobjekten geladen. Dadurch werden sie in verschiedenen Namensräumen innerhalb der Host-Java-Anwendung platziert. Da die Klassendateien für Applets aus verschiedenen Quellen in separaten Namensräumen abgelegt werden, darf der Code eines böswilligen Applets nicht direkt in Klassendateien eingreifen, die von einer anderen Quelle heruntergeladen wurden.

Zusammenarbeit zwischen Klassenladern

Häufig stützt sich ein Klassenladeobjekt auf andere Klassenladeprogramme - zumindest auf den ursprünglichen Klassenladeprogramm -, um einige der Klassenladeanforderungen zu erfüllen, die auf ihn zukommen. Stellen Sie sich beispielsweise vor, Sie schreiben eine Java-Anwendung, die einen Klassenlader installiert, dessen besondere Art des Ladens von Klassendateien durch Herunterladen über ein Netzwerk erreicht wird. Angenommen, während der Ausführung der Java-Anwendung wird von Ihrem Klassenladeprogramm eine Anforderung zum Laden einer Klasse mit dem Namen gestellt Volcano.

Eine Möglichkeit, den Klassenlader zu schreiben, besteht darin, ihn zuerst den ursprünglichen Klassenlader bitten zu lassen, die Klasse zu finden und aus seinem vertrauenswürdigen Repository zu laden. In diesem Fall Volcanowird davon ausgegangen, dass der ursprüngliche Klassenlader keine Klasse mit dem Namen finden kann , da er nicht Teil der Java-API ist Volcano. Wenn der ursprüngliche Klassenladeprogramm antwortet, dass er die Klasse nicht laden kann, könnte Ihr Klassenladeprogramm versuchen, die VolcanoKlasse auf benutzerdefinierte Weise zu laden , indem er sie über das Netzwerk herunterlädt. Angenommen, Ihr Klassenladeprogramm konnte eine Klasse herunterladen Volcano, könnte diese VolcanoKlasse dann eine Rolle im zukünftigen Ausführungsverlauf der Anwendung spielen.

Um mit demselben Beispiel fortzufahren, wird angenommen, dass einige Zeit später Volcanozum ersten Mal eine Klassenmethode aufgerufen wird und dass die Methode auf Klassen Stringaus der Java-API verweist . Da die Referenz zum ersten Mal vom laufenden Programm verwendet wird, fordert die virtuelle Maschine Ihren Klassenlader (den geladenen Volcano) zum Laden auf String. Wie zuvor übergibt Ihr Klassenladeprogramm die Anforderung zuerst an den ursprünglichen Klassenladeprogramm. In diesem Fall kann das ursprüngliche Klassenladeprogramm jedoch eine StringKlasse an Ihr Klassenladeprogramm zurückgeben.

Der ursprüngliche Klassenlader musste Stringzu diesem Zeitpunkt höchstwahrscheinlich nicht tatsächlich geladen werden, da er, da es sich Stringum eine so grundlegende Klasse in Java-Programmen handelt, mit ziemlicher Sicherheit zuvor verwendet wurde und daher bereits geladen wurde. Höchstwahrscheinlich hat der ursprüngliche Klassenlader gerade die StringKlasse zurückgegeben, die er zuvor aus dem vertrauenswürdigen Repository geladen hatte.

Da der ursprüngliche Klassenlader die Klasse finden konnte, versucht Ihr Klassenlader nicht, sie über das Netzwerk herunterzuladen. Es wird lediglich die Stringvom ursprünglichen Klassenladeprogramm zurückgegebene Klasse an die virtuelle Maschine übergeben . Ab diesem Zeitpunkt verwendet die virtuelle Maschine diese StringKlasse immer dann , wenn die Klasse Volcanoauf eine benannte Klasse verweist String.

Klassenlader im Sandkasten

In Javas Sandbox ist die Class Loader-Architektur die erste Verteidigungslinie gegen bösartigen Code. Es ist schließlich der Klassenlader, der Code in den JVM-Code bringt - Code, der feindlich sein könnte.

Die Class Loader-Architektur trägt auf zwei Arten zur Java-Sandbox bei:

  1. Es verhindert, dass bösartiger Code den wohlwollenden Code stört.
  2. Es schützt die Grenzen der vertrauenswürdigen Klassenbibliotheken.

Die Klassenladeprogramm-Architektur schützt die Grenzen der vertrauenswürdigen Klassenbibliotheken, indem sichergestellt wird, dass nicht vertrauenswürdige Klassen nicht vorgeben können, vertrauenswürdig zu sein. Wenn eine böswillige Klasse die JVM erfolgreich dazu verleiten könnte, zu glauben, dass es sich um eine vertrauenswürdige Klasse aus der Java-API handelt, könnte diese böswillige Klasse möglicherweise die Sandbox-Barriere durchbrechen. Indem verhindert wird, dass nicht vertrauenswürdige Klassen sich als vertrauenswürdige Klassen ausgeben, blockiert die Klassenladearchitektur einen möglichen Ansatz zur Gefährdung der Sicherheit der Java-Laufzeit.

Namensräume und Schilde

Die Architektur des Klassenladeprogramms verhindert, dass bösartiger Code den wohlwollenden Code stört, indem geschützte Namensräume für Klassen bereitgestellt werden, die von verschiedenen Klassenladeprogrammen geladen werden. Wie oben erwähnt, ist der Namensraum eine Reihe eindeutiger Namen für geladene Klassen, die von der JVM verwaltet werden.

Namensräume tragen zur Sicherheit bei, da Sie praktisch einen Schutzschild zwischen Klassen platzieren können, die in verschiedene Namensräume geladen werden. Innerhalb der JVM können Klassen im selben Namensraum direkt miteinander interagieren. Klassen in verschiedenen Namensräumen können jedoch nicht einmal die Anwesenheit des anderen erkennen, es sei denn, Sie stellen explizit einen Mechanismus bereit, mit dem die Klassen interagieren können. Wenn eine böswillige Klasse nach dem Laden den Zugriff auf jede andere Klasse garantiert hat, die derzeit von der virtuellen Maschine geladen wird, kann diese Klasse möglicherweise Dinge lernen, die sie nicht wissen sollte, oder die ordnungsgemäße Ausführung Ihres Programms beeinträchtigen.

Erstellen einer sicheren Umgebung

Wenn Sie eine Anwendung schreiben, die Klassenladeprogramme verwendet, erstellen Sie eine Umgebung, in der der dynamisch geladene Code ausgeführt wird. Wenn die Umgebung frei von Sicherheitslücken sein soll, müssen Sie beim Schreiben Ihrer Anwendungs- und Klassenladeprogramme bestimmte Regeln befolgen. Im Allgemeinen sollten Sie Ihre Anwendung so schreiben, dass bösartiger Code vor wohlwollendem Code geschützt ist. Außerdem sollten Sie Klassenladeprogramme so schreiben, dass sie die Grenzen vertrauenswürdiger Klassenbibliotheken wie der Java-API schützen.

Namensräume und Codequellen

Um die Sicherheitsvorteile von Namensräumen zu nutzen, müssen Sie sicherstellen, dass Sie Klassen aus verschiedenen Quellen über verschiedene Klassenlader laden. Dies ist das oben beschriebene Schema, das von Java-fähigen Webbrowsern verwendet wird. Die von einem Webbrowser ausgelöste Java-Anwendung erstellt normalerweise ein anderes Applet-Klassenladeobjekt für jede Klasse von Klassen, die über das Netzwerk heruntergeladen werden. Beispielsweise würde ein Browser ein Klassenladeobjekt verwenden, um Klassen von //www.niceapplets.com herunterzuladen, und ein anderes Klassenladeprogrammobjekt, um Klassen von //www.meanapplets.com herunterzuladen.

Beschränkte Pakete schützen

Mit Java können Klassen im selben Paket sich gegenseitig spezielle Zugriffsrechte gewähren, die Klassen außerhalb des Pakets nicht gewährt werden. Wenn Ihr Klassenladeprogramm eine Anforderung zum Laden einer Klasse erhält, die sich mit ihrem Namen dreist als Teil der Java-API deklariert (z. B. eine Klasse mit dem Namen java.lang.Virus), sollte Ihr Klassenladeprogramm vorsichtig vorgehen. Wenn eine solche Klasse geladen ist, kann sie einen speziellen Zugriff auf die vertrauenswürdigen Klassen von erhalten java.langund diesen speziellen Zugriff möglicherweise für falsche Zwecke verwenden.

Folglich würden Sie normalerweise einen Klassenlader schreiben, der sich einfach weigert, eine Klasse zu laden, die behauptet, Teil der Java-API (oder einer anderen vertrauenswürdigen Laufzeitbibliothek) zu sein, die jedoch nicht im lokalen vertrauenswürdigen Repository vorhanden ist. Mit anderen Worten, nachdem Ihr Klassenladeprogramm eine Anforderung an den ursprünglichen Klassenladeprogramm übergeben hat und das ursprüngliche Klassenladeprogramm angibt, dass es die Klasse nicht laden kann, sollte Ihr Klassenladeprogramm überprüfen, ob die Klasse sich nicht als Mitglied deklariert eines vertrauenswürdigen Pakets. In diesem Fall sollte Ihr Klassenladeprogramm eine Sicherheitsausnahme auslösen, anstatt zu versuchen, die Klasse über das Netzwerk herunterzuladen.

Bewachung verbotener Pakete

Darüber hinaus haben Sie möglicherweise einige Pakete im vertrauenswürdigen Repository installiert, die Klassen enthalten, die Ihre Anwendung über den ursprünglichen Klassenlader laden soll, auf die Sie jedoch nicht für Klassen zugreifen möchten, die über Ihren Klassenlader geladen werden. Angenommen, Sie haben ein Paket mit dem Namen erstellt absolutepowerund im lokalen Repository installiert, auf das der ursprüngliche Klassenladeprogramm zugreifen kann. Angenommen, Sie möchten nicht, dass Klassen, die von Ihrem Klassenladeprogramm geladen werden, eine Klasse aus dem absolutepowerPaket laden können . In diesem Fall würden Sie Ihren Klassenlader so schreiben, dass er als Erstes sicherstellt, dass sich die angeforderte Klasse nicht als Mitglied der Klasse deklariertabsolutepowerPaket. Wenn eine solche Klasse angefordert wird, sollte Ihr Klassenladeprogramm eine Sicherheitsausnahme auslösen, anstatt den Klassennamen an den ursprünglichen Klassenladeprogramm zu übergeben.

Der Klassenlader kann nur anhand des Namens der Klasse erkennen, ob eine Klasse aus einem eingeschränkten Paket wie z. B. java.langoder einem verbotenen Paket wie z. B. absolutepowerstammt. Daher muss einem Klassenladeprogramm eine Liste der Namen von eingeschränkten und verbotenen Paketen gegeben werden. Da der Name der Klasse java.lang.Virusangibt, dass sie aus dem java.langPaket stammt und java.langin der Liste der eingeschränkten Pakete aufgeführt ist, sollte Ihr Klassenladeprogramm eine Sicherheitsausnahme auslösen, wenn der ursprüngliche Klassenladeprogramm sie nicht laden kann. Da der Name der Klasse absolutepower.FancyClassLoaderangibt, dass sie Teil des absolutepowerPakets ist und das absolutepowerPaket in der Liste der verbotenen Pakete enthalten ist, sollte Ihr Klassenladeprogramm ebenfalls eine Sicherheitsausnahme auslösen.

Ein sicherheitsbewusster Klassenlader

Eine übliche Methode zum Schreiben eines sicherheitsbewussten Klassenladeprogramms besteht darin, die folgenden vier Schritte auszuführen:

  1. Wenn Pakete vorhanden sind, von denen dieser Klassenlader nicht laden darf, prüft der Klassenlader, ob sich die angeforderte Klasse in einem der oben genannten verbotenen Pakete befindet. In diesem Fall wird eine Sicherheitsausnahme ausgelöst. Wenn nicht, wird mit Schritt zwei fortgefahren.

  2. Der Klassenlader leitet die Anforderung an den ursprünglichen Klassenlader weiter. Wenn der ursprüngliche Klassenlader die Klasse erfolgreich zurückgibt, gibt der Klassenlader dieselbe Klasse zurück. Andernfalls wird mit Schritt drei fortgefahren.

  3. Wenn vertrauenswürdige Pakete vorhanden sind, zu denen dieser Klassenlader keine Klassen hinzufügen darf, prüft der Klassenlader, ob sich die angeforderte Klasse in einem dieser eingeschränkten Pakete befindet. In diesem Fall wird eine Sicherheitsausnahme ausgelöst. Wenn nicht, fahren Sie mit Schritt vier fort.

  4. Schließlich versucht der Klassenlader, die Klasse auf benutzerdefinierte Weise zu laden, z. B. indem er sie über ein Netzwerk herunterlädt. Bei Erfolg wird die Klasse zurückgegeben. Wenn dies nicht erfolgreich ist, wird der Fehler "Keine Klassendefinition gefunden" ausgegeben.

Durch Ausführen der oben beschriebenen Schritte eins und drei schützt der Klassenladeprogramm die Grenzen der vertrauenswürdigen Pakete. Mit Schritt eins wird verhindert, dass eine Klasse aus einem verbotenen Paket überhaupt geladen wird. In Schritt drei kann sich eine nicht vertrauenswürdige Klasse nicht in ein vertrauenswürdiges Paket einfügen.

Fazit

Die Klassenladearchitektur trägt auf zweierlei Weise zum Sicherheitsmodell der JVM bei:

  1. durch Aufteilen von Code in mehrere Namensräume und Platzieren eines "Schildes" zwischen Code in verschiedenen Namensräumen
  2. durch Schutz der Grenzen vertrauenswürdiger Klassenbibliotheken wie der Java-API

Diese beiden Funktionen der Class Loader-Architektur von Java müssen von Programmierern ordnungsgemäß verwendet werden, um den Sicherheitsvorteil zu nutzen, den sie bieten. Um das Namensraumschild nutzen zu können, sollte Code aus verschiedenen Quellen über verschiedene Klassenladeobjekte geladen werden. Um von einem vertrauenswürdigen Paketgrenzschutz zu profitieren, müssen Klassenlader so geschrieben werden, dass sie die Namen der angeforderten Klassen anhand einer Liste eingeschränkter und verbotener Pakete überprüfen.

Eine Anleitung zum Schreiben eines Klassenladeprogramms einschließlich Beispielcode finden Sie in Chuck McManis ' JavaWorld- Artikel "Die Grundlagen von Java-Klassenladeprogrammen".

Nächsten Monat

Im Artikel des nächsten Monats werde ich die Diskussion über das Sicherheitsmodell der JVM fortsetzen, indem ich den Klassenprüfer beschreibe.

Bill Venners schreibt seit 12 Jahren professionell Software. Er ist im Silicon Valley ansässig und bietet Software-Beratungs- und Schulungsdienste unter dem Namen Artima Software Company an. Im Laufe der Jahre hat er Software für die Unterhaltungselektronik-, Bildungs-, Halbleiter- und Lebensversicherungsbranche entwickelt. Er hat in vielen Sprachen auf vielen Plattformen programmiert: Assemblersprache auf verschiedenen Mikroprozessoren, C unter Unix, C ++ unter Windows, Java im Web. Er ist Autor des Buches: Inside the Java Virtual Machine, veröffentlicht von McGraw-Hill.

Erfahren Sie mehr über dieses Thema

  • Das Buch The Java Virtual Machine Specification (//www.aw.com/cp/lindholm-yellin.html) von Tim Lindholm und Frank Yellin (ISBN 0-201-63452-X), Teil der Java-Reihe (// www.aw.com/cp/javaseries.html) von Addison-Wesley ist die endgültige Referenz für virtuelle Java-Maschinen.
  • Sicheres Computing mit JavaNow und der Zukunft (ein Whitepaper) // www.javasoft.com/marketing/collateral/security.html
  • Häufig gestellte Fragen zur Applet-Sicherheit

    //www.javasoft.com/sfaq/

  • Low Level Security in Java, von Frank Yellin //www.javasoft.com/sfaq/verifier.html
  • Die Java Security-Startseite

    //www.javasoft.com/security/

  • Siehe die Homepage für feindliche Applets

    //www.math.gatech.edu/~mladue/HostileApplets.html

  • Das Buch Java SecurityHostile Applets, Holes and Antidotes von Dr. Gary McGraw und Ed Felton bietet eine gründliche Analyse von Sicherheitsproblemen im Zusammenhang mit Java. //www.rstcorp.com/java-security.html
  • Frühere Artikel zu "Under The Hood":
  • Die schlanke, mittlere virtuelle Maschine - Gibt eine Einführung in die virtuelle Java-Maschine.
  • Der Lebensstil der Java-Klassendatei - Gibt einen Überblick über die Java-Klassendatei, das Dateiformat, in das alle Java-Programme kompiliert werden.
  • Javas Garbage-Collected-Heap - Gibt einen Überblick über die Garbage-Collection im Allgemeinen und den Garbage-Collected-Heap der Java Virtual Machine im Besonderen.
  • Grundlagen des Bytecodes - Führt die Bytecodes der virtuellen Java-Maschine ein und erläutert insbesondere primitive Typen, Konvertierungsoperationen und Stapeloperationen.
  • Gleitkomma-Arithmetik - Beschreibt die Gleitkomma-Unterstützung der Java Virtual Machine und die Bytecodes, die Gleitkomma-Operationen ausführen.
  • Logik und Arithmetik - Beschreibt die Unterstützung der Java Virtual Machine für logische und ganzzahlige Arithmetik sowie die zugehörigen Bytecodes.
  • Objekte und Arrays - Beschreibt, wie die Java Virtual Machine mit Objekten und Arrays umgeht, und erläutert die relevanten Bytecodes.
  • Ausnahmen - Beschreibt, wie die Java Virtual Machine mit Ausnahmen umgeht, und erläutert die relevanten Bytecodes.
  • Try-finally - Beschreibt, wie die virtuelle Java-Maschine try-finally-Klauseln implementiert, und erläutert die relevanten Bytecodes.
  • Kontrollfluss - Beschreibt, wie die Java Virtual Machine den Kontrollfluss implementiert, und erläutert die relevanten Bytecodes.
  • Die Architektur der Aglets - Beschreibt das Innenleben von Aglets, der autonomen Java-basierten Software-Agententechnologie von IBM.
  • The Point of Aglets - Analysiert den realen Nutzen mobiler Agenten wie Aglets, der autonomen Java-basierten Software-Agententechnologie von IBM.
  • Methodenaufruf und -rückgabe - Beschreibt die vier Möglichkeiten, mit denen die virtuelle Java-Maschine Methoden aufruft, einschließlich der relevanten Bytecodes.
  • Thread-Synchronisation - Zeigt, wie die Thread-Synchronisation in der virtuellen Java-Maschine funktioniert. Erläutert die Bytecodes zum Betreten und Verlassen von Monitoren.
  • Javas Sicherheitsarchitektur - Gibt einen Überblick über das in die JVM integrierte Sicherheitsmodell und zeigt die integrierten Sicherheitsfunktionen der JVM.

Diese Geschichte "Sicherheit und die Klassenladearchitektur" wurde ursprünglich von JavaWorld veröffentlicht.