Führen Sie den nicht vertrauenswürdigen Code in einem eigenen Thread aus. Dies verhindert beispielsweise Probleme mit Endlosschleifen und dergleichen und erleichtert die zukünftigen Schritte. Lassen Sie den Haupt-Thread warten, bis der Thread fertig ist. Wenn er zu lange dauert, beenden Sie ihn mit Thread.stop. Thread.stop ist veraltet, aber da der nicht vertrauenswürdige Code keinen Zugriff auf Ressourcen haben sollte, wäre es sicher, ihn zu beenden.
Legen Sie einen SecurityManager für diesen Thread fest. Erstellen Sie eine Unterklasse von SecurityManager, die checkPermission (Permission perm) überschreibt, um einfach eine SecurityException für alle Berechtigungen mit Ausnahme einiger weniger auszulösen . Hier finden Sie eine Liste der Methoden und der erforderlichen Berechtigungen: Berechtigungen im Java TM 6 SDK .
Verwenden Sie einen benutzerdefinierten ClassLoader, um den nicht vertrauenswürdigen Code zu laden. Ihr Klassenladeprogramm wird für alle Klassen aufgerufen, die der nicht vertrauenswürdige Code verwendet, sodass Sie beispielsweise den Zugriff auf einzelne JDK-Klassen deaktivieren können. Die Sache zu tun ist, eine weiße Liste der erlaubten JDK-Klassen zu haben.
Möglicherweise möchten Sie den nicht vertrauenswürdigen Code in einer separaten JVM ausführen. Während die vorherigen Schritte den Code sicherer machen würden, gibt es eine ärgerliche Sache, die der isolierte Code noch tun kann: so viel Speicher wie möglich zuweisen, wodurch der sichtbare Footprint der Hauptanwendung wächst.
JSR 121: Application Isolation API Specification wurde entwickelt, um dieses Problem zu lösen, hat aber leider noch keine Implementierung.
Dies ist ein ziemlich detailliertes Thema, und ich schreibe das meistens aus dem Kopf.
Aber trotzdem, ein unvollkommener, auf eigenes Risiko verwendbarer, wahrscheinlich fehlerhafter (Pseudo-) Code:
ClassLoader
class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name is white-listed JDK class) return super.loadClass(name);
return findClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the untrusted class data here
}
}
Sicherheitsmanager
class MySecurityManager extends SecurityManager {
private Object secret;
public MySecurityManager(Object pass) { secret = pass; }
private void disable(Object pass) {
if (pass == secret) secret = null;
}
// ... override checkXXX method(s) here.
// Always allow them to succeed when secret==null
}
Faden
class MyIsolatedThread extends Thread {
private Object pass = new Object();
private MyClassLoader loader = new MyClassLoader();
private MySecurityManager sm = new MySecurityManager(pass);
public void run() {
SecurityManager old = System.getSecurityManager();
System.setSecurityManager(sm);
runUntrustedCode();
sm.disable(pass);
System.setSecurityManager(old);
}
private void runUntrustedCode() {
try {
// run the custom class's main method for example:
loader.loadClass("customclassname")
.getMethod("main", String[].class)
.invoke(null, new Object[]{...});
} catch (Throwable t) {}
}
}
Thread.stop
verursacht Probleme im Java-Bibliothekscode. Ebenso erfordert der Java-Bibliothekscode Berechtigungen. Viel besser zuzulassen, dass dieSecurityManager
verwendenjava.security.AccessController
. Der Klassenlader sollte wahrscheinlich auch den Zugriff auf die eigenen Klassen des Benutzercodes ermöglichen.System.setSecurityManager(…)
sich dies auf die gesamte JVM auswirkt, nicht nur auf den Thread, der diese Methode aufruft, wurde die Idee, Sicherheitsentscheidungen basierend auf dem Thread zu treffen, aufgegeben, als Java von 1.0 auf 1.1 umgestellt wurde. Zu diesem Zeitpunkt wurde erkannt, dass nicht vertrauenswürdiger Code vertrauenswürdigen Code aufrufen kann und umgekehrt, unabhängig davon, welcher Thread den Code ausführt. Kein Entwickler sollte den Fehler wiederholen.Offensichtlich wirft ein solches System alle möglichen Sicherheitsbedenken auf. Java verfügt über ein strenges Sicherheits-Framework, das jedoch nicht trivial ist. Die Möglichkeit, es zu vermasseln und einem nicht privilegierten Benutzer den Zugriff auf wichtige Systemkomponenten zu ermöglichen, sollte nicht übersehen werden.
Abgesehen von dieser Warnung müssen Sie, wenn Sie Benutzereingaben in Form von Quellcode vornehmen, diese zunächst in Java-Bytecode kompilieren. AFIAK, dies kann nicht nativ durchgeführt werden, daher müssen Sie einen Systemaufruf an javac durchführen und den Quellcode zu Bytecode auf der Festplatte kompilieren. Hier ist ein Tutorial, das als Ausgangspunkt dafür verwendet werden kann. Bearbeiten : Wie ich in den Kommentaren erfahren habe, können Sie Java-Code aus der Quelle nativ mit javax.tools.JavaCompiler kompilieren
Sobald Sie einen JVM-Bytecode haben, können Sie ihn mit der defineClass- Funktion eines ClassLoaders in die JVM laden . Um einen Sicherheitskontext für diese geladene Klasse festzulegen, müssen Sie eine ProtectionDomain angeben . Der minimale Konstruktor für eine ProtectionDomain erfordert sowohl eine CodeSource als auch eine PermissionCollection . Die PermissionCollection ist das Objekt, das Sie hier hauptsächlich verwenden. Sie können damit die genauen Berechtigungen angeben, über die die geladene Klasse verfügt. Diese Berechtigungen sollten letztendlich vom AccessController der JVM erzwungen werden .
Hier gibt es viele mögliche Fehlerpunkte, und Sie sollten äußerst vorsichtig sein, um alles vollständig zu verstehen, bevor Sie etwas implementieren.
quelle
Die Java-Sandbox ist eine Bibliothek zum Ausführen von Java-Code mit begrenzten Berechtigungen. Es kann verwendet werden, um nur auf eine Reihe von Klassen und Ressourcen auf der weißen Liste zuzugreifen. Es scheint nicht in der Lage zu sein, den Zugriff auf einzelne Methoden einzuschränken. Dazu wird ein System mit einem benutzerdefinierten Klassenladeprogramm und einem Sicherheitsmanager verwendet.
Ich habe es nicht benutzt, aber es sieht gut gestaltet und ziemlich gut dokumentiert aus.
@waqas hat eine sehr interessante Antwort gegeben, die erklärt, wie dies möglich ist, sich selbst zu implementieren. Es ist jedoch viel sicherer, solchen sicherheitskritischen und komplexen Code Experten zu überlassen.
Beachten Sie jedoch, dass das Projekt seit 2013 nicht mehr aktualisiert wurde und von den Erstellern als "experimentell" beschrieben wird. Die Homepage ist verschwunden, der Eintrag in Source Forge bleibt jedoch erhalten.
Beispielcode angepasst von der Projektwebsite:
quelle
Nun, es ist sehr spät, Vorschläge oder Lösungen zu geben, aber ich hatte immer noch ein ähnliches Problem, eher forschungsorientiert. Grundsätzlich habe ich versucht, eine Bereitstellung und automatische Auswertungen für Programmieraufgaben für Java-Kurse in E-Learning-Plattformen bereitzustellen.
Ich weiß, dass dies ziemlich komplex und mit vielen Aufgaben verbunden ist, aber Oracle Virtual Box bietet bereits eine Java-API zum dynamischen Erstellen oder Klonen von virtuellen Maschinen. https://www.virtualbox.org/sdkref/index.html (Hinweis: Selbst VMware bietet dafür eine API.)
Informationen zur Mindestgröße und Konfiguration der Linux-Distribution finden Sie hier http://www.slitaz.org/en/ ,
Wenn die Schüler es nun vermasseln oder versuchen, dies zu tun, kann es sein, dass er seine eigene VM beschädigen kann, möglicherweise mit Speicher oder Dateisystem oder Netzwerk, Socket.
Auch intern in diesen VMs können Sie zusätzliche Sicherheit wie Sandbox (Sicherheitsmanager) für Java bereitstellen oder benutzerspezifische Konten unter Linux erstellen und so den Zugriff einschränken.
Hoffe das hilft !!
quelle
Hier ist eine thread-sichere Lösung für das Problem:
https://svn.code.sf.net/p/loggifier/code/trunk/de.unkrig.commons.lang/src/de/unkrig/commons/lang/security/Sandbox.java
Bitte kommentieren!
CU
Arno
quelle
Um das Problem in der akzeptierten Antwort zu beheben, bei der der benutzerdefinierte Benutzer
SecurityManager
für alle Threads in der JVM und nicht für jeden Thread gilt, können Sie einen benutzerdefinierten Benutzer erstellenSecurityManager
, der für bestimmte Threads wie folgt aktiviert / deaktiviert werden kann:ToggleSecurirtyManagerPermission
ist nur eine einfache Implementierung von,java.security.Permission
um sicherzustellen, dass nur autorisierter Code den Sicherheitsmanager aktivieren / deaktivieren kann. Es sieht aus wie das:quelle
Sie müssen wahrscheinlich einen benutzerdefinierten SecurityManger und / oder AccessController verwenden . Ausführliche Informationen finden Sie in der Java-Sicherheitsarchitektur und in anderen Sicherheitsdokumentationen von Sun.
quelle