Exécutez le code non approuvé dans son propre thread. Cela évite par exemple les problèmes de boucles infinies et autres, et facilite les étapes futures. Demandez au thread principal d'attendre que le thread se termine, et si cela prend trop de temps, supprimez-le avec Thread.stop. Thread.stop est obsolète, mais comme le code non approuvé ne devrait avoir accès à aucune ressource, il serait prudent de le tuer.
Définissez un SecurityManager sur ce thread. Créez une sous-classe de SecurityManager qui remplace checkPermission (Permission perm) pour simplement lancer une SecurityException pour toutes les autorisations sauf quelques-unes. Il existe une liste de méthodes et des autorisations dont elles ont besoin ici: Autorisations dans le SDK Java TM 6 .
Utilisez un ClassLoader personnalisé pour charger le code non approuvé. Votre chargeur de classe serait appelé pour toutes les classes utilisées par le code non approuvé, vous pouvez donc faire des choses comme désactiver l'accès aux classes JDK individuelles. La chose à faire est d'avoir une liste blanche des classes JDK autorisées.
Vous souhaiterez peut-être exécuter le code non approuvé dans une machine virtuelle Java distincte. Alors que les étapes précédentes rendraient le code sûr, il y a une chose ennuyeuse que le code isolé peut encore faire: allouer autant de mémoire que possible, ce qui augmente l'empreinte visible de l'application principale.
JSR 121: La spécification d'API d'isolation d'application a été conçue pour résoudre ce problème, mais malheureusement, elle n'a pas encore d'implémentation.
C'est un sujet assez détaillé, et j'écris principalement tout cela par le haut de ma tête.
Mais de toute façon, du code imparfait, à utiliser à vos risques et périls, probablement bogué (pseudo):
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
}
}
Responsable de la sécurité
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
}
Fil
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
causera des problèmes dans le code de la bibliothèque Java. De même, le code de la bibliothèque Java nécessitera des autorisations. Beaucoup mieux pour permettre l'SecurityManager
utilisationjava.security.AccessController
. Le chargeur de classe devrait probablement également autoriser l'accès aux propres classes du code utilisateur.System.setSecurityManager(…)
cela affectera l'ensemble de la JVM, pas seulement le thread invoquant cette méthode, l'idée de prendre des décisions de sécurité basées sur le thread a été abandonnée lorsque Java est passé de 1.0 à 1.1. À ce moment, il a été reconnu que du code non approuvé peut invoquer du code approuvé et vice versa, quel que soit le thread qui exécute le code. Aucun développeur ne doit répéter l'erreur.De toute évidence, un tel système soulève toutes sortes de problèmes de sécurité. Java a un cadre de sécurité rigoureux, mais ce n'est pas anodin. La possibilité de tout foutre en l'air et de laisser un utilisateur non privilégié accéder aux composants vitaux du système ne doit pas être négligée.
Cet avertissement mis à part, si vous prenez une entrée utilisateur sous forme de code source, la première chose à faire est de la compiler en bytecode Java. AFIAK, cela ne peut pas être fait en natif, vous devrez donc faire un appel système à javac et compiler le code source en bytecode sur le disque. Voici un tutoriel qui peut être utilisé comme point de départ pour cela. Edit : comme je l'ai appris dans les commentaires, vous pouvez en fait compiler le code Java à partir des sources de manière native en utilisant javax.tools.JavaCompiler
Une fois que vous disposez du bytecode JVM, vous pouvez le charger dans la JVM à l'aide de la fonction defineClass d' un ClassLoader . Pour définir un contexte de sécurité pour cette classe chargée, vous devrez spécifier un ProtectionDomain . Le constructeur minimal d'un ProtectionDomain requiert à la fois un CodeSource et un PermissionCollection . Le PermissionCollection est l'objet de votre utilisation principale ici - vous pouvez l'utiliser pour spécifier les autorisations exactes de la classe chargée. Ces autorisations doivent finalement être appliquées par AccessController de la JVM .
Il y a beaucoup de points d'erreur possibles ici, et vous devez être extrêmement prudent pour tout comprendre complètement avant de mettre en œuvre quoi que ce soit.
la source
Le Java Sandbox est une bibliothèque pour exécuter du code Java avec un nombre limité d'autorisations. Il peut être utilisé pour autoriser l'accès uniquement à un ensemble de classes et de ressources sur liste blanche. Il ne semble pas être en mesure de restreindre l'accès à des méthodes individuelles. Il utilise un système avec un chargeur de classe personnalisé et un gestionnaire de sécurité pour y parvenir.
Je ne l'ai pas utilisé mais il a l'air bien conçu et raisonnablement bien documenté.
@waqas a donné une réponse très intéressante expliquant comment il est possible de l'implémenter soi-même. Mais il est beaucoup plus sûr de laisser ce code critique et complexe à des experts.
Notez cependant que le projet n'a pas été mis à jour depuis 2013 et que les créateurs le décrivent comme "expérimental". Sa page d'accueil a disparu mais l'entrée Source Forge demeure.
Exemple de code adapté du site Web du projet:
la source
Pour résoudre le problème dans la réponse acceptée selon laquelle la personnalisation
SecurityManager
s'appliquera à tous les threads de la JVM, plutôt que sur une base par thread, vous pouvez créer une personnalisationSecurityManager
qui peut être activée / désactivée pour des threads spécifiques comme suit:ToggleSecurirtyManagerPermission
est juste une simple implémentation dejava.security.Permission
pour s'assurer que seul le code autorisé peut activer / désactiver le gestionnaire de sécurité. Cela ressemble à ceci:la source
Eh bien, il est très tard pour donner des suggestions ou des solutions, mais j'étais toujours confronté à un problème similaire, un peu plus axé sur la recherche. Fondamentalement, j'essayais de fournir une disposition et des évaluations automatiques pour les affectations de programmation pour le cours Java dans les plates-formes d'apprentissage en ligne.
Je sais que cela semble une tâche assez complexe et beaucoup de tâches, mais Oracle Virtual Box fournit déjà une API Java pour créer ou cloner des machines virtuelles de manière dynamique. https://www.virtualbox.org/sdkref/index.html (Notez que même VMware fournit également une API pour faire de même)
Et pour la taille minimale et la configuration de la distribution Linux, vous pouvez vous référer à celle-ci ici http://www.slitaz.org/en/ ,
Alors maintenant, si les étudiants gâchent ou essaient de le faire, peut-être avec la mémoire ou le système de fichiers ou le réseau, le socket, au maximum, il peut endommager sa propre VM.
Également en interne dans ces machines virtuelles, vous pouvez fournir une sécurité supplémentaire comme Sandbox (gestionnaire de sécurité) pour Java ou créer des comptes spécifiques à l'utilisateur sur Linux et ainsi restreindre l'accès.
J'espère que cela t'aides !!
la source
Voici une solution thread-safe pour le problème:
https://svn.code.sf.net/p/loggifier/code/trunk/de.unkrig.commons.lang/src/de/unkrig/commons/lang/security/Sandbox.java
Commentez s'il vous plaît!
CU
Arno
la source
Vous devrez probablement utiliser un SecurityManger et / ou un AccessController personnalisé . Pour plus de détails, consultez Java Security Architecture et d' autres documents sur la sécurité de Sun.
la source