Sonntag, 7. September 2008
Wie privat ist private eigentlich wirklich?
In so gut wie jeder Einsteigerlektüre für die Sprache Java wird gelehrt, dass Datenkapselung mit eine der wichtigsten Voraussetzungen für eine saubere, objetorientierte Programmierung ist. In der Regel genügt es den Autoren darauf hinzuweisen, dass Attribute als private oder protected deklariert und nur über entsprechende Zugriffsmethoden nach außen zum Lesen oder ggf. auch Schreiben erreichbar gemacht werden sollen. - Wenn man sich die Sprache Java etwas genauer ansieht, reicht dies allerdings leider nicht immer aus...

Da Java über das Feature der Reflection vefügt, ist es möglich, sich hierüber Informationen über die Methoden und eben auch Attribute einzelner Klassen zu informieren. - Dazu gehören natürlich auch diejenigen, die als private oder protected deklariert sind.

Angenommen, wir interessieren uns für den Inhalt des als private deklarierten Attributs value der Klasse String (auch wenn man da zugegebenermaßen auch einfacher dran kommen kann). Dann ist es möglich, eine Referenz auf dieses Attribut mit Hilfe der Methoden der Reflection-API zu erlangen:

String st = "Hans";
Class<? extends String> stringClass = st.getClass();
Field valueField = stringClass.getDeclaredField("value");

Auf obige Weise erlang man natürlich erst generelle Informationen über das Attribut value, nicht allerdings den Inhalt des Attributs einer konkreten String-Instanz. Doch auch hier ist die Reflection-API hilfreich:

char[] value = (char[])valueField.get(st);

In der Standardkonfiguration wird ein solcher Zugriff allerdings mit dem Auftreten einer IllegalAccessException quittiert, was uns also noch nicht wirklich zu dem gewünschten Inhalt führt. - Hierzu ist noch eine kleine Veränderung notwendig. Über die Methode setAccessible des Field-Objetks ist es nämlich möglich, genau dieses prüfende Verhalten der Methode Field.get(Object) auszuschalten:

valueField.setAccessible(true);
char[] value = (char[])valueField.get(st);
System.out.println(Arrays.toString(value));

So ist es nun nicht nur möglich, den Inhalt des eigentlich versteckten Arrays auszulesen, sondern, da die Inhalte eines Arrays anders als ein Array selbst nicht als final deklariert werden können, denInhalt des Arrays auch zu verändern:

value[2] = 'u';
System.out.println(st);

Die Ausgabe ist nun, nicht wie erwartet "Hans" sondern hat sich zu "Haus" verändern. Das Objekt vom Typ String, welches theoretisch zwar unveränderbar sein sollte, ist über einen kleinen Umweg auf einmal doch veränderbar geworden...

Eine totale Katastrophe ist dies für das Sichheitskonzept der Sprache Java natürlich nicht, denn durch setzen der "suppressAccessChecks"-Permission innerhalb des zuständigen SecurityManagers kann genau die für den Zugriff notwendige Field.setAccessible-Methode verboten werden. - Klar ist allerdings auch, dass die meisten (auch serverseitig eingestzten) Java-Umgebungen mit den Standardeinstellungen laufen, in denen gerade genau diese Änderung am SecurityManager nicht vorgenommen wurde...

... link (0 Kommentare)   ... comment