Ich arbeite derzeit an der Entwicklung einer kleinen Java-Anwendung, in der vertrauenswürdiger Code neben nicht vertrauenswürdigem Code ausgeführt werden muss. Um dies zu erreichen, habe ich eine benutzerdefinierte SecurityManager
installiert, die SecurityException
s jedes Mal wirft, wenn eine Berechtigung überprüft wird.Warum verursacht mein benutzerdefinierter SecurityManager beim 16. Mal, wenn ich ein Objekt mit Constructor.newInstance erzeuge, Ausnahmen?
Als eine Brücke zwischen dem vertrauenswürdigen und nicht vertrauenswürdigen Code habe ich einen Thread, der Constructor.newInstance()
verwendet, um ein Objekt eines nicht vertrauenswürdigen Typs zu instanziieren. Zu dem Zeitpunkt, an dem dieser Aufruf ausgeführt wird, ist der Sicherheitsmanager so konfiguriert, dass er alles blockiert. Interessanterweise, die ersten 15 mal, dass ich versuche, Objekte mit Constructor.newInstance()
zu erstellen, funktioniert alles gut, aber das 16. Mal bekomme ich eine SecurityException
.
Ich habe es geschafft, dies zu einem einfachen Testprogramm runter:
import java.lang.reflect.*;
import java.security.*;
public class Main {
/* Track how many instances have been created so that we can see when the exception
* is thrown.
*/
private static int numInstances = 0;
public Main() {
System.out.println("Number created: " + ++numInstances);
}
public static void main(String[] args) {
/* Get the constructor for Main so that we can instantiate everything
* later on.
*/
Constructor<Main> ctor;
try {
ctor = Main.class.getConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
return;
}
/* Install a super prohibitive security manager that disallows all operations. */
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission p) {
/* Nothing is allowed - any permission check causes a security
* exception.
*/
throw new SecurityException("Not permitted: " + p);
}
});
/* Continuously create new Main objects. */
try {
while (true) {
ctor.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
Dieses Programm installiert eine SecurityManager
deren checkPermission
immer eine Ausnahme auslöst, unabhängig davon, welche die Erlaubnis beantragt wird. Es sitzt dann in einer Schleife und verwendet ctor.newInstance()
, um ein harmloses Objekt Main
zu instanziieren, das die Anzahl der bisher generierten Instanzen ausgibt. Die Ausgabe dieses Programms, auf meinem System, ist wie folgt:
Number created: 1
Number created: 2
Number created: 3
Number created: 4
Number created: 5
Number created: 6
Number created: 7
Number created: 8
Number created: 9
Number created: 10
Number created: 11
Number created: 12
Number created: 13
Number created: 14
Number created: 15
java.lang.SecurityException: Not permitted: ("java.lang.RuntimePermission" "createClassLoader")
at Main$1.checkPermission(Main.java:32)
at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:611)
at java.lang.ClassLoader.checkCreateClassLoader(ClassLoader.java:274)
at java.lang.ClassLoader.<init>(ClassLoader.java:316)
at sun.reflect.DelegatingClassLoader.<init>(ClassDefiner.java:72)
at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:60)
at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:58)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:57)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:396)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:395)
at sun.reflect.MethodAccessorGenerator.generateConstructor(MethodAccessorGenerator.java:94)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:48)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at Main.main(Main.java:39)
Nach the Javadoc for RuntimePermission
, die createClassLoader
Erlaubnis mit hohen Risiken behaftet zu gewähren:
Dies ist eine extrem gefährliche Erlaubnis zu erteilen. Schädliche Anwendungen, die ihre eigenen Klassenladeprogramme instanziieren können, können dann ihre eigenen Rogue-Klassen in das System laden. Diese neu geladenen Klassen können vom Klassenlader in jede Schutzdomäne platziert werden, wodurch den Klassen automatisch die Berechtigungen für diese Domäne erteilt werden.
Ich habe zwei Fragen:
Was speziell diesen Fehler verursacht? Warum bekomme ich zum 16. Mal eine Anfrage für einen Classloader? Ich vermute, das hat damit zu tun, dass Java versucht, die Reflexion zu optimieren, indem ich Bytecode erzeuge, um das Objekt direkt zu instantiieren, aber ich bin mir nicht sicher.
Ohne Whitelisting das Privileg
createClassLoader
, das gefährlich ist, gibt es eine Möglichkeit, die nicht vertrauenswürdigen Objekte aus vertrauenswürdigem Code zu instanziieren?Gehe ich grundsätzlich auf die falsche Weise?
Vielen Dank!
Ich habe versucht, Ihren Code, das gleiche Verhalten. Wenn Sie die throw-Ausnahme entfernen und eine print-Anweisung hinzufügen, wird die checkPermission dreimal aufgerufen, bevor die 16. Instanz erstellt wird. –