java sucks

Die Package-Struktur ist flach, nicht hierarchisch. Die Punkte sind rein kosmetisch und beeinflussen nicht das Scoping.

Es gibt keine enums!!

Es gibt keine templates!

Es gibt keine Globalen Variablen, dafür statics innerhalb eines Packages.

Java-Interface ist eine Klasse mit nur abstrakten Methoden und ohne Felder. Als einzige Variable sind static final “Variable” (in Wirklichkeit Konstanten) erlaubt.

Jede Klasse wird ein File. –> Tausend kleine Dateien. Lädt ewig, ist ineffizient.

Nachteile von gegebener Garbage Collection: Man kann keinen eigenen (besseren) Garbage Collector schreiben. Und auch keinen besseren Allocator. James Gosling sagt dazu:
“[Garbage Collection] can interfere with time critical applications. You should design systems to be judicious in the number of objects they create.”

Garbage Collection verhindert schnelle Antwortzeit (im Millisekundenbereich).

Kein Präprozessor! Keine Makros. Immer System.out.println(“fobar”). Nicht abkürzbar.

Der Garbage-Collector ruft finalize von allen Objekten auf, die freigegeben werden. Eine Endlosschleife in einem Finalizer läßt den Garbage-Collector-Thread hängen –> Fehler schwer zu finden.

Finalizer müssen *explizit* den Finalizer der Basis-Klasse aufrufen! Das sollte der Compiler tun!

Wrapper-Klassen für Integer, Float, Double, … die immutable sind. D.h. man kann Integer, … nicht als Var-Parameter and Methoden vergeben. Alle Objekte sind Call-by-Reference, d.h. wenn man einen Integer als Var übergeben will, muß man eine Wrapper-Klasse neuschreiben, weil die Standard-Wrapper-Klasse immutable ist.

Type Cast geht, ist sogar notwendig, und erzeugt Laufzeit-Verluste!

Java ist nicht definiert. Was Sun gerade implementiert, heißt “Java”. Sun hat z.B. irgendwann in der Mitte die Scoping-Regeln geändert, um eine Security-Race-Condition zu fixen. Inkompatibel geändert.

bar+”” –> Stringify (“magic”) — geht auch bei Nicht-Klassen (ints)

Keine Multidimensionalen Arrays. Nur Arrays von Arrays. (schlecht für Type-Check)

Arrays sind [laut Sun] keine Klassen.
Wenn man eine Methode aufruft davon, die es nicht gibt, dann sagt javac, daß die Klasse Object die Methode nicht hat. Außerdem kann man Arrays auf einen Stack pushen.

Nur ein Monitor. D.h. man kann nicht für Lesen mehrere Zugriffe zulassen und für Schreiben nur einen.

Security-Problem: synchronized-Block auf alle Objekte anwendbar, auch auf System-Objekte. So sind Denial-Of-Service-Attacken nicht verhinderbar. Sun hat verlautbaren lassen, daß Denial-Of-Service-Probleme geringe Priorität hätten.

Aus dem lokalen File-System kommender Byte-Code genießt vollstes Vertrauen. –> Per AFS von sonstwo geholte Klassen dürfen alles.

Da der Javac in Java geschrieben ist, und die Standard-Sun-Java-Umgebung benutzt, kann man nicht in Standard-Klassen herumexperimentieren, ohne daß der Java-Compiler abstürzt.

Statischer Type-Check bei Array-Zugriffen nicht möglich. Beispiel: Wenn A ein Subtyp von B ist, dann ist A[] ein Subtyp von B[]. void proc(B[] x, B y) { x[0]=y; } ist für den Fall ungültig, daß x vom Typ A[] ist und y vom Typ B.

Die Standard-SecurityManager-Klasse schmeißt ständig SecurityExceptions. Es bleibt dem Implementierer überlassen, eine Subklasse zu definieren, die [bei Netscape anhand des Call Stacks] entscheidet, ob ein Zugriff gültig ist.

accept() kann benutzt werden, um eine Verbindung anzunehmen. Der Gegenstelle muß man nur sagen, wo der Browser sitzt. Das kann geschehen über Covert Channels, die nicht zu verhindern sind. Beispiel: DNS-Lookup von einem unbekannten Host, gibt dem zuständigen DNS-Server einen nahezu beliebigen String. Dieser Channel geht auch durch Firewalls durch!

Sun behauptet, Datei-ACLs implementiert zu haben. Tatsächlich haben sie nur eine Liste von privilegierten Dateien implementiert. Die Defaults sind aber fahrlässig gesetzt. So kann man unter Windows in C:\TEMP schreiben (aber nicht lesen). D.h. man kann die Platte füllen. Und man kann Temp-Dateien von anderen trashen und so andere Applikationen zum Absturz bringen.

getenv() kann herausfinden, wie der User heißt, was für Software installiert ist, wo das Home-Verzeichnis liegt. So wurde getenv entfernt und zu “system properties” getan. Trotzdem kann man auch diese lesen — über ein unlängst gefundenes Sicherheits-Problem.

Java kann die Systemzeit lesen und damit Benchmarks durchführen. Wenn Java also auf einem Production-System gefahren würde, dann könnte die Konkurrenz von der Existenz des Super-Rechners erfahren.

Java läßt Applets auf IP-Adressen zugreifen, von denen ein Teil des Applet geladen wurde. Die Auflösung Name-IP-Nummer macht aber ein fremder Server. Der kann lügen. Im Namen kann man auch die IP-Adresse kodieren.

{1,2,3} nur im Initializer (“int[] a = {1,2,3}”) erlaubt, nicht in Zuweisungen oder Vergleichen. Nicht zu motivieren.

Sun-typisch: Tausend ungeprüfte sprintf-Calls mit User Supplied Data. So könnten Leute, die Java-Klassen disassemblieren, ihre Maschine kompromittieren.

In HotJava kann ein Applet den Proxy ändern!!! Der Proxy kann den gesamten Verkehr mithören, inkl. Passwörtern!

Threads können System-Threads nicht beeinflussen, aber andere Applet-Threads. D.h. man kann einen Lurker schreiben, der alle Animators abschießt oder buggy und langsam erscheinen läßt.

Der Java-Compiler erlaubt nicht, daß man eine Klasse definiert, deren Konstruktor nicht als erstes den Konstruktor einer Superklasse oder einen Konstruktor der selben Klasse aufruft. Der Bytecode-Verifier checkt das aber nicht. So kann man Bytecode hacken, der den ClassLoader erbt und den geerbten construktor nicht aufruft — und damit Typ-Checks ausschalten und sogar native Methoden aufrufen.

Durch einen Bug werden Klassen, deren Name mit einem “/” beginnt, direkt aus dem Filesystem geladen. In Verbindung mit dem Netscape-Cache ergibt sich, daß sie, wenn sie herausfinden kann, wo Netscape die Cache-Daten abspeichert ($HOME/.netscape/cache/URL-Hash), ihre Kopie “aus dem lokalen Filesystem” laden kann. Dateien aus dem lokalen Filesystem wird vollständig vertraut!

Bytecode ist linear statt hierarchisch. –> Erst Recht schwer zu checken.

Es gibt keine formale Beschreibung von Java oder dem Java-Typ-System. Die Sicherheit von Java basiert aber 100%ig auf dem Java-Typ-System. Sie kann also nicht verifiziert werden. Wir können auch keine formalen Aussagen über Libraries treffen, die in Java geschrieben sind.

Die Packages sehen zwar hierarchisch aus, sind es aber nicht. So kann man nicht Package-Scoping für Sicherheit benutzen.

Man kann Rechte nicht flexibel gestalten in Java — gar kein Zugriff oder totaler Zugriff.

Methoden können aus dem Konstruktor heraus aufgerufen werden und sehen evtl. ein halb initialisiertes Objekt. Auch überschrieben Methoden können aufgerufen werden. Die Sicherheit wird hier also in die Hände des Programmierers gelegt.

Ein neues Objekt wird erzeugt, indem eine uninitialisierte Instanz erzeugt wird, die wird auf den Stack kopiert, dann wird ihr Konstruktor aufgerufen. Der Konstruktor ändert dann die Typ-Signatur. So weit zu statischem Typing.

“private” wird vom Bytecode Verifier nicht erzwungen für aus dem Filesystem geladene Klassen. Jede Klasse aus dem Paket java.lang kann den Security-Manager setzen, obwohl system.setSecurityManager eigentlich nicht danach aussieht.

HotJava und Netscape geben keine Security-Policy vor. Das wird vom Orange Book gefordert:
“There must be an explicit and well-defined security policy enforced by the system.”
Ohne eine solche Policy ist nicht definiert, wie sich eine sichere Implementation verhalten soll.

Der SecurityManager ist als Reference Monitor gedacht. Es gibt drei Anforderungen:
er wird immer aufgerufen
er ist hack-sicher
er ist verifizierbar
In allen drei Bereichen gibt es Schwächen im Design bei Java:
er wird nicht automatisch aufgerufen, sondern der Programmierer des Runtime-Systems muß ihn von Hand aufrufen. Wenn er es vergißt, wird immer Zugriff gewährt. Normale Policy muß sein, immer den Zugriff zu verweigern, wenn nicht explizit erlaubt.
er ist nicht hack-sicher, weil er eine “protected” Variable hatte, die von Subklassen geändert werden konnte. Das ist inzwischen gefixt worden, indem die protected Semantik geändert wurde.
er ist nicht verifizierbar, weil er in einer nicht definierten Sprache, Java, geschrieben wurde. Und tatsächlich hatten sowohl die JDK als auch die Netscape Implementation Bugs im SecurityManager.

Java beinhaltet keine klar ausgezeichnete Trusted Computing Base. Verteilte Teile des Systemes müssen zusammenarbeiten, um Sicherheit zu erreichen. Der Bytecode-Verifier und der Interpreter oder Code-Generator — alles große und unübersichtliche Programme — müssen zusammenarbeiten. Der HotJava-Browser darf seine Interna nicht freigeben. Das Ziel in der Literatur ist eine kleine, wohldefinierte, verifizierbare TCB.

Eine fundamentale Forderung, die von Sun traditionell nicht eingehalten wird, ist der Audit Trail. Sicherheitsrelevante Software muß eine nachträgliche Prüfung zulassen. Hackversuche werden bei Java nirgends gelogt.

Thread-Accounting ist wichtig, aber nicht da. Man kann nicht sehen, welche Threads gerade laufen, und Threads killen.

Es wäre wünschenswert, in Java Spiele zu implementieren. Das erfordert schnelle Libraries, d.h. man müßte Laufzeit-Checks wegoptimieren. Das geht bei Java nicht.

Es wäre schön, Videokonferenz-Tools in Java zu implementieren. Dazu brauchen Applets Zugriff auf Mikrophon und Videokamera. Genau das, was man auch zum Abhören des Benutzers braucht.

Es wäre nett, parallele Berechnungen wie Primfaktor-Berechnung in Java zu implementieren. Doch das erzwingt, daß Threads laufen, nachdem der User die Page verlassen hat. Das ist momentan auch so.
So, that’s why JAVA sucks, in a nutshell.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s