Comment créer un sandbox Java?


Je veux faire mon application pour exécuter le code d'autres personnes, aka plugins. Cependant, quelles options ai-je pour sécuriser cela afin qu'ils n'écrivent pas de code malveillant. Comment puis-je contrôler ce qu'ils peuvent ou ne peuvent pas faire?

Je suis tombé sur le fait que JVM a une fonctionnalité "bac à sable intégré" - qu'est-ce que c'est et est-ce le seul moyen? Existe-t-il des bibliothèques Java tierces pour créer un bac à sable?

Quelles options ai-je? Des liens vers des guides et des exemples sont appréciés!

Author: Lii, 2009-11-11

6 answers

Vous recherchez un responsable de la sécurité. Vous pouvez restreindre les autorisations d'une application en spécifiant une stratégie .

 23
Author: tangens, 2011-02-28 12:11:38
  • Définir et enregistrer votre propre gestionnaire de sécurité vous permettra de limiter ce que fait le code - voir la documentation oracle pour SecurityManager .

  • Envisagez également de créer un mécanisme distinct pour charger le code - c'est-à-dire que vous pouvez écrire ou instancier un autre Classloader pour charger le code à partir d'un endroit spécial. Vous pouvez avoir une convention pour charger le code-par exemple à partir d'un répertoire spécial ou d'un zip spécialement formaté fichier (sous forme de fichiers WAR et de fichiers JAR). Si vous écrivez un classloader, cela vous met dans la position de devoir travailler pour charger le code. Cela signifie que si vous voyez quelque chose (ou une dépendance) que vous souhaitez rejeter, vous pouvez simplement ne pas charger le code. http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html

 18
Author: daf, 2013-04-11 21:49:28

Jetez un oeil àle projet java-sandbox qui permet de créer facilement des sandbox très flexibles pour exécuter du code non fiable.

 5
Author: Arno Mittelbach, 2014-03-11 16:54:52

Pour une application AWT/Swing, vous devez utiliser une classe AppContext non standard, qui peut changer à tout moment. Donc, pour être efficace, vous devez démarrer un autre processus pour exécuter du code de plug-in et gérer la communication entre les deux (un peu comme Chrome). Le plug-in processus aurez besoin d'un SecurityManager et une ClassLoader pour isoler le plug-in code et approprié ProtectionDomain plug-dans les classes.

 4
Author: Tom Hawtin - tackline, 2009-11-11 13:31:29

Voici comment le problème peut être résolu avec un SecurityManager:

Https://svn.code.sf.net/p/loggifier/code/trunk/de.unkrig.commons.lang/src/de/unkrig/commons/lang/security/Sandbox.java

package de.unkrig.commons.lang.security;

import java.security.AccessControlContext;
import java.security.Permission;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

import de.unkrig.commons.nullanalysis.Nullable;

/**
 * This class establishes a security manager that confines the permissions for code executed through specific classes,
 * which may be specified by class, class name and/or class loader.
 * <p>
 * To 'execute through a class' means that the execution stack includes the class. E.g., if a method of class {@code A}
 * invokes a method of class {@code B}, which then invokes a method of class {@code C}, and all three classes were
 * previously {@link #confine(Class, Permissions) confined}, then for all actions that are executed by class {@code C}
 * the <i>intersection</i> of the three {@link Permissions} apply.
 * <p>
 * Once the permissions for a class, class name or class loader are confined, they cannot be changed; this prevents any
 * attempts (e.g. of the confined class itself) to release the confinement.
 * <p>
 * Code example:
 * <pre>
 *  Runnable unprivileged = new Runnable() {
 *      public void run() {
 *          System.getProperty("user.dir");
 *      }
 *  };
 *
 *  // Run without confinement.
 *  unprivileged.run(); // Works fine.
 *
 *  // Set the most strict permissions.
 *  Sandbox.confine(unprivileged.getClass(), new Permissions());
 *  unprivileged.run(); // Throws a SecurityException.
 *
 *  // Attempt to change the permissions.
 *  {
 *      Permissions permissions = new Permissions();
 *      permissions.add(new AllPermission());
 *      Sandbox.confine(unprivileged.getClass(), permissions); // Throws a SecurityException.
 *  }
 *  unprivileged.run();
 * </pre>
 */
public final
class Sandbox {

    private Sandbox() {}

    private static final Map<Class<?>, AccessControlContext>
    CHECKED_CLASSES = Collections.synchronizedMap(new WeakHashMap<Class<?>, AccessControlContext>());

    private static final Map<String, AccessControlContext>
    CHECKED_CLASS_NAMES = Collections.synchronizedMap(new HashMap<String, AccessControlContext>());

    private static final Map<ClassLoader, AccessControlContext>
    CHECKED_CLASS_LOADERS = Collections.synchronizedMap(new WeakHashMap<ClassLoader, AccessControlContext>());

    static {

        // Install our custom security manager.
        if (System.getSecurityManager() != null) {
            throw new ExceptionInInitializerError("There's already a security manager set");
        }
        System.setSecurityManager(new SecurityManager() {

            @Override public void
            checkPermission(@Nullable Permission perm) {
                assert perm != null;

                for (Class<?> clasS : this.getClassContext()) {

                    // Check if an ACC was set for the class.
                    {
                        AccessControlContext acc = Sandbox.CHECKED_CLASSES.get(clasS);
                        if (acc != null) acc.checkPermission(perm);
                    }

                    // Check if an ACC was set for the class name.
                    {
                        AccessControlContext acc = Sandbox.CHECKED_CLASS_NAMES.get(clasS.getName());
                        if (acc != null) acc.checkPermission(perm);
                    }

                    // Check if an ACC was set for the class loader.
                    {
                        AccessControlContext acc = Sandbox.CHECKED_CLASS_LOADERS.get(clasS.getClassLoader());
                        if (acc != null) acc.checkPermission(perm);
                    }
                }
            }
        });
    }

    // --------------------------

    /**
     * All future actions that are executed through the given {@code clasS} will be checked against the given {@code
     * accessControlContext}.
     *
     * @throws SecurityException Permissions are already confined for the {@code clasS}
     */
    public static void
    confine(Class<?> clasS, AccessControlContext accessControlContext) {

        if (Sandbox.CHECKED_CLASSES.containsKey(clasS)) {
            throw new SecurityException("Attempt to change the access control context for '" + clasS + "'");
        }

        Sandbox.CHECKED_CLASSES.put(clasS, accessControlContext);
    }

    /**
     * All future actions that are executed through the given {@code clasS} will be checked against the given {@code
     * protectionDomain}.
     *
     * @throws SecurityException Permissions are already confined for the {@code clasS}
     */
    public static void
    confine(Class<?> clasS, ProtectionDomain protectionDomain) {
        Sandbox.confine(
            clasS,
            new AccessControlContext(new ProtectionDomain[] { protectionDomain })
        );
    }

    /**
     * All future actions that are executed through the given {@code clasS} will be checked against the given {@code
     * permissions}.
     *
     * @throws SecurityException Permissions are already confined for the {@code clasS}
     */
    public static void
    confine(Class<?> clasS, Permissions permissions) {
        Sandbox.confine(clasS, new ProtectionDomain(null, permissions));
    }

    // Code for 'CHECKED_CLASS_NAMES' and 'CHECKED_CLASS_LOADERS' omitted here.

}
 3
Author: Arno Unkrig, 2014-08-06 14:22:51

La discussion sur cette question m'a inspiré à démarrer mon propre projet sandbox.

Https://github.com/Black-Mantha/sandbox

Dans ce document, je suis tombé sur une question de sécurité importante: "Comment autorisez-vous le code en dehors du bac à sable à contourner le SecurityManager?"

Je mets le code sandbox dans son propre ThreadGroup, et accorde toujours l'autorisation en dehors de ce groupe. Si vous devez de toute façon exécuter du code privilégié dans ce groupe (dans un rappel, par exemple), vous pouvez utiliser un ThreadLocal pour définir un indicateur pour ce thread uniquement. Le classloader empêchera le sandbox d'accéder au ThreadLocal. De plus, si vous faites cela, vous devez interdire l'utilisation des finaliseurs, car ils s'exécutent dans un thread dédié en dehors du ThreadGroup.

 0
Author: Black Mantha, 2017-12-11 19:18:55