Access denied (“java.net.SocketPermission”…) mit Java 8

Hallo,

ich habe ein Java Applet, das in einer einfachen HTML-Seite eingefügt ist:

<applet width="100%" height="100%" id="StatApplet" code="stat.applet.StatApplet.class" archive="stat.jar">
    <PARAM NAME="_cx" VALUE="25903">
    <PARAM NAME="_cy" VALUE="19738">
    <param name="frame" value="0">
    <param name="module" value="1">
    <param name="count" value="4">
    <param name="image" value="RSload.gif">
    <param name="boxbgcolor" value="#ffffff">
    <param name="boxmessage" value="Monitor loading">
</applet>

Das Applet ist signiert mit einem Zertifikat von GlobalSign. Die JAR- und die HTML-Datei wurden auf einen Embedded Web-Server (ein Beck IPC SC143) kopiert, der unter http://192.168.0.91/ erreichbar ist. Das Applet öffnen nun eine Socket-Verbindung zu dem Server, von dem es geladen wurde:

    final int CONNECT_ETHERNET_TIMEOUT_MS = 5000;
    final int PORT_STATUSMON = 945;

    String host = getCodeBase().getHost();  // get host address
    if (host.equals("")) {
        host = getParameter("host");    // to run applet from eclipse
    }
    InetAddress inetAddress = InetAddress.getByName(host);

    Socket ethernetSocket = new Socket();
    ethernetSocket.connect(new InetSocketAddress(inetAddress, PORT_STATUSMON), CONNECT_ETHERNET_TIMEOUT_MS);

    ethernetSocket.close();
} catch (Exception e) {
    e.printStackTrace();
}```

Das funktionierte bisher prima, zuletzt mit 7 Update 45, aber seit dem Update der VM auf Java 8 Update 25 bekomme ich diese Exception:


java.security.AccessControlException: access denied (“java.net.SocketPermission” “192.168.0.91:945” “connect,resolve”)



Die Exception wird in connect() geworfen.  Wie das?  Ein Applet darf doch Verbindungen zu dem Server aufbauen, von dem es geladen wurde, oder ist das neuerdings nicht mehr so?

Jürgen

Das ist soweit korrekt, ein Applet darf (durfte ?) eine Verbindung zu seinem “Heimat-Server” aufbauen, was du auch korrekt machst. Jedoch wird dir laut Exception bereits das resolve verweigert, also schon die Auflösung deines Host-Namen (ja, auch eine IP-Adresse ist erstmal immer noch ein Host-Name, erst die entsprechende Implementierung macht daraus wirklich eine numerische IP). Wenn wir mal schnell Google fragen kommt dabei folgendes raus : es sind nur noch URL-Verbindungen gestattet, und das einigen Aussagen nach auch nur noch auf bestimmten Standard-Ports. Eine eigene Socket-Verbindung ist so nicht mehr ohne weiteres erlaubt.
Ich hatte schon mal ein ähnliches Problem und dabei wer der Output des “Servers” sehr interessant : das Applet setzt eine HTTP-GET-Anfrage nach einer crossdomain.xml ab. Fragt man Google wiederum danach kommt als Ergebnis : ReleaseNote Java6Update10. Diese Einschränkungen wurde mit dem “NextGen Java-Plugin”-Update in j6u10 bereits implementiert, wurde aber bis Java8 nur eher sporadisch umgesetzt. Seit dem letzten Java7 Update und seit dem Major-Release von Java8 ist das ganze aber mitlerweile extrem restriktiv geworden so das bei einer normalen Socket-Verbindung dieses crossdomain.xml verlangt wird. Zu finden hier : http://www.oracle.com/technetwork/java/javase/plugin2-142482.html#CROSSDOMAINXML
Laut dieser ReleaseNote war es am Anfang nur für nicht-signierte Applets, dann für selbst-signierte und mitlerweile auch für Applets die über ein “trusted-CA” verfügen wie z.B. deins (“tusted-CA” bedeutet das die CA im CA-Speicher von Java liegt).

Um es einfach zu machen : wenn möglich sollte man erstmal überhaupt keine Applets mehr einsetzen. Stattdessen würde ich wenn dann schon eher WebStart empfehlen oder eben selbst was deployen.
Sonst kann man versuchen es auf HTTP umzubrechen und mit URLConnection auf TCP/80 zu arbeiten (also quasi in den WebServer ein entsprechendes BackEnd einpflegen).
Wenn es wirklich eine RAW-Verbindung sein muss bleibt nichts übrig als die HTTP-GET beim Server mit einer entsprechenden dummy-XML zu beantworten.

Auf die Probleme mit j6u10 war ich bei meiner Recherche auch schon gestoßen, auch auf die crossdomain.xml. Wenn ich meinem Wireshark glauben darf, wird auf die in meinem Fall aber nicht zugegriffen. Ich habe sie trotzdem mal als Placebo auf den Embedded Webserver geladen, so sieht sie aus:

<?xml version="1.0"?>
<cross-domain-policy>
   <site-control permitted-cross-domain-policies="master-only"/>
   <allow-http-request-headers-from domain="*" headers="*"/>
   <allow-access-from domain="*" />
</cross-domain-policy>

Sie hat an meinem Problem nichts geändert (logisch, mangels GET), ich muss auch zugeben, mich noch nicht näher mit den Möglichkeiten darin befasst zu haben.

[quote=Sen-Mithrarin]Wenn wir mal schnell Google fragen kommt dabei folgendes raus : es sind nur noch URL-Verbindungen gestattet, und das einigen Aussagen nach auch nur noch auf bestimmten Standard-Ports. Eine eigene Socket-Verbindung ist so nicht mehr ohne weiteres erlaubt.[/quote] Auf welchen Artikel beziehst Du dich? Ich habe das bei Oracle so konkret nicht finden können.

[quote=Sen-Mithrarin;104124]wenn möglich sollte man erstmal überhaupt keine Applets mehr einsetzen.[/quote] Das sehe ich inzwischen auch so, habe aber ein recht umfangreiches Applet in Pflege und möchte das möglichst nicht neu schreiben.

Mit URLConnection werde ich mal experimentieren, mein Embeded Server würde grundsätzlich auch eine Kommunikation über ein CGI auf Port 80 erlauben, statt auf 945.

Jürgen

Vielleicht hilft dir dieser Byte-Welt-Wiki Beitrag in irgendeiner Weise weiter: Java Applets starten - ab Java 7 Update 51

*** Edit ***

Auch beim Einbinden von Applets gibt es Neues. Dieser Wiki-Beitrag kann helfen: Einbinden von Java-Applets - Permission-Attribut

Was ich persönlich noch mehr als ziemlich Banane finde ist das mit dem Signieren in der Regel die Sandbox komplett ausgehebelt wird. Das da Oracle nicht viel mehr als einen zusätzlichen -Tag und ein Eintrag ins Manifest einfällt ist eigentlich nur noch armseelig, but what ever …

Nein, ernsthaft, wenn sich mal ansieht für was Java ursprünglich gedacht war, wofür es dann genutzt wurde und was es heute ist dann kann man eigentlich nur den Kopf schütteln und muss zugeben das da so einiges ziemlich schief gelaufen ist. Klar, es gab in der Vergangenheit teils schwere Sicherheitslücken, aber mir kann keiner erzählen das es DAS PERFEKTE System gäbe, man wird überall Lücken finden, man muss sie nur suchen. Eher im Gegenteil : Java ist mit dem impliziten Boundary-Check anderen Sprachen weit vorraus und macht so schon automatisch die Lücke von Überläufen und Ausführen von eingeschleustem Code zu. Daran sollte man mal in C arbeiten oder ein vergleichbares Konzept einführen, wenn auch nur als Framework. Denn die meisten “Probleme” entstehen ja durch “falsche” Pointer-Arithmetik (wozu braucht man den Mist überhaupt ?) und fehlende Boundary-Prüfungen, das ist nun mal leider Fakt.

Mal noch ganz nebenbei :

@TO
Vermeide nach Möglichkeit bitte Cross-Posts : [noparse]http://www.java-forum.org/netzwerkeprogrammierung/163331-access-denied-java-net-socketpermission-java-8-a.html[/noparse], oder weise wenn dann bitte wenigstens drauf hin.

Danke für den Hinweis, ich war mir nicht sicher, wo meine Frage besser aufgeghoben ist (jetzt weiß ich es) :slight_smile:

*** Edit ***

Inzwischen habe ich diesen Thread gefunden:

Dort wird auch auf die entsprechende Doku von Oracle hingewiesen:

Wie es aussieht, ist es aus der Sandbox von Java 8 nicht mehr möglich, Verbindungen zum Heimat-Host auf anderen Ports aufzubauen. Ich werde daher jetzt versuchen, mein Applet auf all-permissions umzustellen (signiert ist es ja, könnte also klappen).

*** Edit ***

So, das hat geklappt, mit all-permissions kann ich die Sockets wieder normal benutzen.

So geht’s:

[ul]
[li]Das Applet-Tag um die Permissions erweitern:[/li]

<applet width="100%" height="100%" id="StatApplet" code="stat.applet.StatApplet.class" archive="stat.jar">
<param name="permissions" value="all-permissions">
...

[li]Die gleiche Permission ins MANIFEST.MF eintragen:[/li]

Manifest-Version: 1.0
Application-Name: Status Monitor
Permissions: all-permissions
...

[li]Das JAR mit einem Zertifikat einer anerkannten CA (bei mir GlobalSign) signieren.[/li][/ul]
Leider hat das Applet jetzt eigentlich viel zu viele Rechte, aber das nehme ich in Kauf.

Vielen Dank an alle, hab’ wieder was gelernt.

Jürgen

Und wie gesagt : genau DAS kann ich leider mal überhaupt nicht verstehen : man versucht die Sicherheit zu erhöhen in dem man halt eigentlich so gut wie alles sperrt, verhaut es aber so dermaßen das wenn man nur ein bisschen was will eigentlich die komplette sandbox und damit die Sicherheit die man damit eigentlich erreichen will komplett umgeht. Klar kann man in den Permissions auch nur eingeschränkte Attribute angeben, aber der Mensch an sich ist halt faul so das er mit großer Wahrscheinlichkeit nur aus reiner Bequemlichkeit all-permissions nutzen wird. Für mich mal wieder absolutes Fehl-Konzept, aber davon hat Oracle schon so einige hingelegt seit Sun aufgekauft wurde. Ich weis nicht was die falsch machen um eine eigentlich so wunderschöne Sprache so verkommen zu lassen, denn Applets waren einst mal das Hauptaufgabengebiet von Java.

Ich hab selbst noch mal kurz drüber geguckt :
Um es noch mal für die zusammenzufassen die das gleiche Problem haben :

Es sind nur noch URLConnection über das gleiche Protokoll erlaubt. Sprich : wenn das Applet über HTTP geladen wurde ist auch nur HTTP erlaubt, kein HTTPS. Wenn über HTTPS geladen wurde genau umgekehrt : nur HTTPS, kein HTTP. Und andere Protokolle und Ports sowie Sockets überhaupt nicht.

Kann man das wirklich?

Ich lese unter 11.3.6 Security, dass nur sandbox, all-permissions oder default möglich sind, also entweder darf das Applet alles oder nichts, oder?

Jürgen

Stimmt, hast recht, das wird ja immer hust , ironie besser ironie off. Ne mal im enrst ohne Spaß jetzt : wie kann man so beschränkt sein sich so ein dämliches Konzept ausdenken zu müssen : “Mama, wir sperren einfach mal alles …” und dann als Ausweichmöglichkeit nur “block” oder “no-block” zu geben statt wie in Richtung Android mit entsprechenden Permission-Gruppen. Klar, Applets sind “ausgestorben”, aber auch noch vorsätzlich so abschießen, da könnte sie es gleich komplett aus der SE-API entfernen und sagen : tja, ist halt so.