Java Security Manager Deprecation - Pro und Kontra (?)

01.12.2024

Nachdem der Security Manager in Java ja nun abgekündigt ist, wollte ich mich noch einmal ausführlich darum kümmern, was dieses Konzept eigentlich kann und was nicht- und ob es letztlich verdient auf dem Scheiterhaufen landet.

Zunächst sei einmal ein kleiner Exkurs gestattet: In einem C-Programm, das auf einem POSIX-kompatiblen System ausgeführt werden kann kann man einzelne Privilegien bzw. Capabilities "droppen" - das heißt, dass die Anwendung von sich aus sagt: ich brauche bestimmte Funktionalitäten nicht. Kurz gesagt macht man damit einem erfolgreichen Angriff, der es schafft, Code im Kontext der Anwendung auszuführen das Leben schwer. Ein Beispiel: Eine Anwendung, die nur über Sockets mit anderen Prozessen kommuniziert muss weder Dateien lesen noch welche schreiben. Schafft es ein Angreifer aber nun, eine dort vorhandene Sicherheitslücke auszunutzen, kann er im Kontext der Anwendung und mit den Rechten des Prozesses Dateien im System lesen und schreiben - obwohl das im Code der Anwendung nie vorgesehen war. Macht sich aber die Anwendung die Mühe, diese Fähigkeiten zu Beginn der Ausführung offiziell zu "droppen", schafft es der bösartige Code nun auch nicht mehr, Dateien zu lesen oder zu schreiben. Das nennt man auch Angriffsoberflächenminimierung.

Man könnte seine Anwendung jetzt noch dekomponieren - Weiß man zum Beispiel, dass Multimedia-Codecs in der Vergangenheit immer wieder Einfallstore für Schädlinge gewesen sind kann man die Anwendung in mehrere Prozesse dekomponieren, die miteinander kooperieren: Der eigentliche Hauptprozess lädt die Multimediadateien in den Ram und gibt sie über eine Interprozesskommunikationsschnittstelle an einen zweiten weiter, der praktisch alle Privilegien gedroppt hat außder denen die zur Kommunikation mit dem anderen Prozess gebraucht werden. In diesem zweiten kann die Dekodierung der Multimediadaten geschehen und wenn erfolgreich werden diese an den Hauptprozess zurückgegeben. In diesem Szenario ist es wesentlich schwieriger, durch eine Lücke in einer der Bibliotheken zur Arbeit mit Multimediainhalten Schaden am Gesamtsystem zu verursachen.

Das könnte man auch als Grundgedanke an den Permissions des SecurityManeger in Java annehmen.

Allerdings ist das Konzept hier ein anderes: Der SecurityManegr arbeitet nicht auf Prozessbasis, sondern auf Basis der CodeBase und damit auf der Basis der einzelnen Jar-Dateien, aus denen eine Java-Anwendung besteht.

Und ein weiterer großer Unterschied ist, dass es hier nicht um Betriebssystem-Funktionalitäten geht sondern um die der Virtuellen Maschine. Damit komme ich zu der Frage, die den eigentlichen Grund für das Schreiben dieses Artikels darstellt: Schützt der SecurityManager wirklich alle Java-Anwendungen?

Daraus ergaben sich zwei Teilfragen, die sich aus folgendem Gedanken ergeben: Es ist möglich, Code innerhalb einer VM auszuführen, der nicht aus kompiliertem ByteCode besteht. Damit ist Teilfrage eins: greifen die Sicherheitsmaßnahmen des SecurityManager bei Skript-Code, der über die mit JSR-223 eingeführten Mechanismen ausgeführt wird? Und greifen die Sicherheitsmaßnahmen des SecurityManager bei Code, der in kompilierten DLLs vorliegt und per JNI bzw. JNA in die Anwendung integriert wurde?

Ich habe dazu ein kleines Experiment erstellt - es handelt sich dabei um 5 Klassen - eine davon ruft die anderen auf. Diese sind wiederum sehr einfach gestrickt - sie geben lediglich einen kurzen Text in eine Datei aus. Dann deaktiviere ich über den SecurityManager das Recht, in eine Datei zu schreiben und teste, ob dies danach auch tatsächlich fehlschlägt.

Die einzelnen Tests waren:

  • In kompiliertem JavaCode
  • In BeanShell per JSR-223
  • in Python per JSR-223 (Jython)
  • in einer DLL per JNI
  • ein Test, den ich ursprünglich vorhatte, war JavaScript, aber ich habe es auch nach stundenlangem Herumprobieren nicht geschafft, die GrallVM-Implementierung zum Funktionieren zu bringen
Der Vollständigkeit halber hier noch zwei Links zum Thema JavaScript und JSR-223.

Für die DLL habe ich auf folgenden Gist zurückgegriffen.

Tatsächlich funktioniert der SecurityManager für geskripteten Code in meinen Tests wie für kompilierten Code. Den Grund dafür vermuite ich in der Tatsache, dass beide Implementationen direkt für die JVM geschrieben wurden und daher während der Interpretation Bytecode erzeugen, der von der VM ausgeführt wird.

Wie ich aber bereits erwartet hatte, sind alle Sicherungen ausgeschaltet, sobald native DLLs ins Spiel kommen: mit der Klasse, die die DLL zum Schreiben der Testdatei benutzt konnte ich die Datei schreiben - egal, ob ich Permissions dafür erteilt hatte oder nicht.

Ich - der ich bisher die Mechanismen des SecurityManager nur dazu verwendet hatte, abhängig vom angemeldeten Nutzer bestimmte Funktionalitäten zu sperren oder freizuschalten - habe bei diesem Experiment viel gelernt: Unter anderem, was immer damit gemeint ist, wenn man liest, dass der SecurityManager aus Java entfernt wird, weil seine Konfiguration so umständlich und zeitaufwändig ist.

Besonders die Einbindung anderer Bibliotheken arbeitete in völlig nervige Arbeit aus, die zu einem großen Teil den Autoren der Bibliotheken anzulasten ist: Sie haben einfach die Tatsache nicht auf dem Schirm gehabt, dass es den SecurityManager gibt und so haben sie jede Methode, die über eine Permission läuft nicht extras gecheckt - was zum Beispiel die Folge hat, dass bei jedem Zugriff auf eine System-Property eine SecurityException fliegt - das könnte man anders machen: Versuche, aucf die Property zuzugreifgen und wenn das nicht geht, dann nimm den Default-Wert an! Ein weiteres Problem ist, dass tatsächlich viele der SecurityExceptions verschluckt werden - in dem Fall muss man erst das security-Debugging korrekt konfigurieren und aktivieren um herauszubekommen, dass das seltsame Verhalten an fehlenden Permissions liegt. Ein weiterer Zeitfresser war die Tatsache, dass Entwickler nicht mit der Tatsache umgehen, dass optionale Dateien wegen fehlender Permissions nicht gelesen werden können. Das führt jedesmal zu einer Exception und der Beendigung der Anwendung, wenn man es meiner Ansicht nach genau wie das Fehlen der jeweiligen Datei behandeln könnte.

Zur Illustration hänge ich hier den Inhalt der Policy an, die ich für mein kleines Experiment benötigt habe...

grant codeBase "file:/home/elbosso/src/language_java/classes/exa.jar" {
	permission java.io.FilePermission "/tmp/exa.txt", "write";
};
grant codeBase "file:/home/elbosso/src/language_java/classes/bsh.jar" {
	permission java.io.FilePermission "/tmp/exa.txt", "write";
};
grant codeBase "file:/home/elbosso/src/language_java/classes/exb.jar" {
	permission java.io.FilePermission "/tmp/exb.txt", "write";
	permission java.lang.RuntimePermission "loadLibrary.hello";
};
grant codeBase "file:/home/elbosso/src/language_java/classes/exc.jar" {
	permission java.io.FilePermission "/tmp/python", "write";
	permission java.io.FilePermission "/home/elbosso/Downloads/jython-standalone-2.7.4.jar", "read";
	permission java.util.PropertyPermission "jnr.ffi.provider", "read";
	permission java.util.PropertyPermission "sun.arch.data.model", "read";
	permission java.util.PropertyPermission "*", "read,write";
	permission java.io.FilePermission ".jython", "read";
	permission java.io.FilePermission "<<ALL FILES>>", "execute";
	permission java.lang.RuntimePermission "getenv.ComSpec";
	permission java.util.PropertyPermission "user.dir", "read";
	permission java.io.FilePermission "/home/elbosso/.jython", "read";
	permission java.lang.RuntimePermission "shutdownHooks";
	permission java.lang.RuntimePermission "createClassLoader";
	permission java.io.FilePermission "<<ALL FILES>>", "read";
	permission java.lang.RuntimePermission "getProtectionDomain";
};
grant codeBase "file:/home/elbosso/Downloads/jython-standalone-2.7.4.jar" {
	permission java.io.FilePermission "/tmp/python", "write";
	permission java.util.PropertyPermission "jnr.ffi.provider", "read";
	permission java.util.PropertyPermission "sun.arch.data.model", "read";
	permission java.util.PropertyPermission "debug", "read";
	permission java.util.PropertyPermission "*", "read,write";
	permission java.io.FilePermission ".jython", "read";
	permission java.io.FilePermission "<<ALL FILES>>", "execute";
	permission java.lang.RuntimePermission "getenv.ComSpec";
	permission java.util.PropertyPermission "user.dir", "read";
	permission java.io.FilePermission "/home/elbosso/.jython", "read";
	permission java.lang.RuntimePermission "shutdownHooks";
	permission java.lang.RuntimePermission "createClassLoader";
	permission java.io.FilePermission "<<ALL FILES>>", "read";
	permission java.lang.RuntimePermission "getProtectionDomain";
};
grant codeBase "file:/home/elbosso/src/language_java/classes/ex.jar" {
	permission java.io.FilePermission "/tmp/exa.txt", "write";
	permission java.io.FilePermission "/tmp/exb.txt", "write";
	permission java.io.FilePermission "/tmp/python", "write";
	permission java.lang.RuntimePermission "loadLibrary.hello";
	permission java.io.FilePermission "/home/elbosso/Downloads/jython-standalone-2.7.4.jar", "read";
	permission java.util.PropertyPermission "jnr.ffi.provider", "read";
	permission java.util.PropertyPermission "sun.arch.data.model", "read";
	permission java.util.PropertyPermission "debug", "read";
	permission java.util.PropertyPermission "*", "read,write";
	permission java.io.FilePermission ".jython", "read";
	permission java.io.FilePermission "<<ALL FILES>>", "execute";
	permission java.lang.RuntimePermission "getenv.ComSpec";
	permission java.util.PropertyPermission "user.dir", "read";
	permission java.io.FilePermission "/home/elbosso/.jython", "read";
	permission java.lang.RuntimePermission "shutdownHooks";
	permission java.lang.RuntimePermission "createClassLoader";
	permission java.io.FilePermission "<<ALL FILES>>", "read";
	permission java.lang.RuntimePermission "getProtectionDomain";
};

Alle Artikel rss Wochenübersicht Monatsübersicht Codeberg Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Syntax-Highlighting für InfluxDB in Java-Anwendungen

    01.12.2019

    Wie bereits in einem früheren Artikel beschrieben beschäftige ich mich derzeit mit Ideen, Echtzeitdatenbanken und speziell InfluxDB in die sQLshell zu integrieren.

    Weiterlesen...

Neueste Artikel

  • Migration der Webseite und aller OpenSource Projekte

    In eigener Sache...

    Weiterlesen...
  • Gnuplot Snippets Projekt revisited

    Ich habe mein Projekt mit Skripts und Skriptfragmenten für Gnuplot wieder einmal überarbeitet und ein wenig erweitert.

    Weiterlesen...
  • Kommando-Palette als Swing Komponente für Java-Anwendungen

    Ich habe - als Fingerübung - eine Komponente für Java Swing Anwendungen erstellt, die ein UX-Muster realisiert, das in den letzten Jahren mehr und mehr adaptiert wird: Die Kommando-Palette.

    Weiterlesen...

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen Codeberg-Repositories findet man hier.