Ejecute el código que no es de confianza en su propio hilo. Esto, por ejemplo, evita problemas con bucles infinitos y demás, y facilita los pasos futuros. Haga que el hilo principal espere a que termine, y si tarda demasiado, elimínelo con Thread.stop. Thread.stop está obsoleto, pero dado que el código que no es de confianza no debería tener acceso a ningún recurso, sería seguro eliminarlo.
Establezca un SecurityManager en ese hilo. Cree una subclase de SecurityManager que anule checkPermission (Permiso de permiso) para simplemente lanzar una SecurityException para todos los permisos excepto unos pocos seleccionados. Hay una lista de métodos y los permisos que requieren aquí: Permisos en Java TM 6 SDK .
Utilice un ClassLoader personalizado para cargar el código que no es de confianza. Se llamaría a su cargador de clases para todas las clases que usa el código que no es de confianza, por lo que puede hacer cosas como deshabilitar el acceso a clases individuales de JDK. Lo que hay que hacer es tener una lista blanca de clases JDK permitidas.
Es posible que desee ejecutar el código que no es de confianza en una JVM separada. Si bien los pasos anteriores harían que el código fuera seguro, hay una cosa molesta que el código aislado todavía puede hacer: asignar tanta memoria como pueda, lo que hace que la huella visible de la aplicación principal crezca.
JSR 121: La especificación de API de aislamiento de aplicaciones fue diseñada para resolver esto, pero desafortunadamente aún no tiene una implementación.
Este es un tema bastante detallado, y sobre todo estoy escribiendo todo esto de la cabeza.
Pero de todos modos, algún código imperfecto, de uso bajo su propio riesgo, probablemente con errores (pseudo) código:
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
}
}
Gerente de seguridad
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
}
Hilo
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
causará problemas en el código de la biblioteca de Java. De manera similar, el código de la biblioteca de Java requerirá permisos. Mucho mejor para permitir elSecurityManager
usojava.security.AccessController
. El cargador de clases probablemente también debería permitir el acceso a las propias clases del código de usuario.System.setSecurityManager(…)
afectará a toda la JVM, no solo al hilo que invoca ese método, la idea de tomar decisiones de seguridad basadas en el hilo se abandonó cuando Java cambió de 1.0 a 1.1. En este momento se reconoció que el código que no es de confianza puede invocar un código de confianza y viceversa, independientemente del hilo que ejecute el código. Ningún desarrollador debería repetir el error.Obviamente, este esquema plantea todo tipo de problemas de seguridad. Java tiene un marco de seguridad riguroso, pero no es trivial. La posibilidad de estropearlo y permitir que un usuario sin privilegios acceda a componentes vitales del sistema no debe pasarse por alto.
Aparte de esa advertencia, si está tomando la entrada del usuario en forma de código fuente, lo primero que debe hacer es compilarlo en el código de bytes de Java. AFIAK, esto no se puede hacer de forma nativa, por lo que deberá realizar una llamada del sistema a javac y compilar el código fuente en bytecode en el disco. Aquí hay un tutorial que puede usarse como punto de partida para esto. Editar : como aprendí en los comentarios, en realidad puede compilar código Java desde la fuente de forma nativa usando javax.tools.JavaCompiler
Una vez que tenga el código de bytes de JVM, puede cargarlo en la JVM usando la función defineClass de ClassLoader . Para establecer un contexto de seguridad para esta clase cargada, deberá especificar un ProtectionDomain . El constructor mínimo de ProtectionDomain requiere tanto CodeSource como PermissionCollection . PermissionCollection es el objeto de uso principal para usted aquí; puede usarlo para especificar los permisos exactos que tiene la clase cargada. El AccessController de JVM debe hacer cumplir estos permisos en última instancia .
Aquí hay muchos puntos de error posibles, y debe tener mucho cuidado de comprender todo completamente antes de implementar cualquier cosa.
fuente
El Java-Sandbox es una biblioteca para la ejecución del código Java con un conjunto limitado de permisos. Se puede utilizar para permitir el acceso solo a un conjunto de clases y recursos incluidos en la lista blanca. No parece poder restringir el acceso a métodos individuales. Utiliza un sistema con un cargador de clases personalizado y un administrador de seguridad para lograr esto.
No lo he usado pero parece bien diseñado y razonablemente bien documentado.
@waqas ha dado una respuesta muy interesante explicando cómo es posible implementarlo usted mismo. Pero es mucho más seguro dejar un código tan complejo y crítico para la seguridad en manos de los expertos.
Sin embargo, tenga en cuenta que el proyecto no se ha actualizado desde 2013 y los creadores lo describen como "experimental". Su página de inicio ha desaparecido pero la entrada de Source Forge permanece.
Código de ejemplo adaptado del sitio web del proyecto:
fuente
Para abordar el problema en la respuesta aceptada por la cual la costumbre
SecurityManager
se aplicará a todos los subprocesos en la JVM, en lugar de por subproceso, puede crear una personalizadaSecurityManager
que se pueda habilitar / deshabilitar para subprocesos específicos de la siguiente manera:ToggleSecurirtyManagerPermission
es solo una implementación simple dejava.security.Permission
para garantizar que solo el código autorizado pueda habilitar / deshabilitar el administrador de seguridad. Se parece a esto:fuente
Bueno, es muy tarde para dar sugerencias o soluciones, pero aún así me enfrentaba a un problema similar, más orientado a la investigación. Básicamente, estaba tratando de proporcionar una provisión y evaluaciones automáticas para tareas de programación para el curso de Java en plataformas de aprendizaje electrónico.
Sé que esto suena bastante complejo y con muchas tareas, pero Oracle Virtual Box ya proporciona la API de Java para crear o clonar máquinas virtuales de forma dinámica. https://www.virtualbox.org/sdkref/index.html (Tenga en cuenta que incluso VMware también proporciona API para hacer lo mismo)
Y para el tamaño mínimo y la configuración de distribución de Linux, puede consultar este aquí http://www.slitaz.org/en/ ,
Así que ahora, si los estudiantes se equivocan o intentan hacerlo, puede ser con la memoria, el sistema de archivos o la red, el socket, como máximo, puede dañar su propia VM.
También internamente en estas VM, puede proporcionar seguridad adicional como Sandbox (administrador de seguridad) para Java o crear cuentas específicas de usuario en Linux y, por lo tanto, restringir el acceso.
Espero que esto ayude !!
fuente
Aquí hay una solución segura para subprocesos para el problema:
https://svn.code.sf.net/p/loggifier/code/trunk/de.unkrig.commons.lang/src/de/unkrig/commons/lang/security/Sandbox.java
¡Por favor comenta!
CU
Arno
fuente
Probablemente necesitará utilizar un SecurityManger y / o AccessController personalizados . Para obtener muchos detalles, consulte Arquitectura de seguridad de Java y otra documentación de seguridad de Sun.
fuente