2012-06-07 7 views
19

Estoy tratando de ejecutar código javascript no confiable en linux + node.js con el módulo sandbox pero está roto, todo lo que necesito es permitir que los usuarios escriban programas javascript que impriman algo de texto. No se permite ninguna otra entrada y solo se utilizará javascript, no hay otros módulos de nodo. Si no es realmente posible hacerlo, ¿qué otro idioma sugiere para este tipo de tarea? El conjunto de características mínimas que necesito es matemáticas, expresiones regulares, manipulación de cadenas y funciones básicas de JSON. Los scripts se ejecutarán por, digamos, 5 segundos como máximo y luego se matará el proceso, ¿cómo puedo lograrlo?¿Cómo ejecutar el servidor de código no confiable?

+1

Puedes usar Ruby. Podría ayudarte con eso. Tiene todas las características (expresiones regulares, matemáticas, cadenas y una biblioteca JSON). También podría usar siempre una idea de sandboxing de más bajo nivel: o bien usa permisos normales, o usa SELinux (pero eso parece ir MUY por la borda). – Linuxios

+0

preferiría javascript, pero ¿podría explicar cómo haría con el código sandboxing ruby? – AlfredoVR

+0

Aquí hay un resumen básico: https://gist.github.com/2890984 que acabo de escribir. La variable global '$ SAFE' de Ruby, cuando se establece en 4 (su valor más alto), evitará prácticamente todo lo que usted desee. No permitirá la E/S, las redes, la mayoría de los accesos a otros objetos que no creó, etc. Y luego podemos usar de forma segura el temido 'eval'. La parte 'Thread' se debe a que a menos que realice el sandboxing en otro hilo, su hilo principal estará sujeto a las mismas restricciones del nivel' $ SAFE' 4. – Linuxios

Respuesta

2

La idea básica de los sandboxes es que necesita variables predefinidas como globales para hacer cosas, por lo que si las rechaza desarmándolas o reemplazándolas por una controlada, no podrá escapar. Mientras no olvides nada.

Primero reemplace deny require() o reemplácelo con algo controlado. No se olvide sobre el proceso y también conocido como "raíz" "global", lo difícil es no olvidar nada, por eso es bueno depender de otra persona de haber construido una caja de arena ;-)

1

hágase las siguientes preguntas:

  1. ¿Eres una de las personas más inteligentes del planeta?
  2. ¿Rechaza rutinariamente las ofertas de trabajo de Google, Mozilla y Kaspersky Lab porque le aburriría?
  3. ¿El "código que no es de confianza" proviene de personas que trabajan en la misma compañía que usted o de delincuentes y aburridos informáticos de todo el mundo?
  4. ¿Estás seguro de que node.js no tiene agujeros de seguridad que puedan filtrarse a través de tu sandbox?
  5. ¿Se puede escribir el código 100% perfecto sin errores?
  6. ¿Sabes todo sobre JavaScript?

Como ya sabe por sus experimentos con el sandbox module, escribir su propio entorno limitado no es trivial. El principal problema con los sandboxes es que debes hacer todo bien. Un error arruinará por completo su seguridad, razón por la cual los desarrolladores de navegadores luchan constantemente contra los crackers de todo el mundo.

Dicho esto, las cajas de arena simples son bastante fáciles de hacer. Primero, tendrá que escribir su propio intérprete de JavaScript porque no puede usar el de node.js debido a eval() y require() (ambos permitirían que los crackers escapen de su sandbox).

El intérprete debe asegurarse de que el código interpretado no puede acceder a nada además de los pocos símbolos globales que usted proporciona. Esto significa que no puede haber una función eval(), por ejemplo (o debe asegurarse de que esta función solo se evalúe en el contexto de su propio intérprete de JavaScript).

Desventaja de este enfoque: Mucho trabajo y si se equivoca con su intérprete, los crackers pueden abandonar el arenero.

Otro enfoque es limpiar el código y ejecutarlo con eval() de node.js. Puede limpiar el código existente ejecutando un montón de expresiones regulares sobre él como /eval\s*[(]//g para eliminar partes del código malicioso.

Desventaja de este enfoque: Es fácil cometer un error que lo hará vulnerable a un ataque. Por ejemplo, puede haber desajuste entre lo que regexp y lo que node.js piensan como "espacio en blanco".Es posible que el intérprete acepte algunos espacios en blanco unicode oscuros, pero no mediante la expresión regular, que permitiría a un atacante ejecutar eval().

Mi sugerencia: Escriba un pequeño caso de prueba de demostración que muestre cómo el módulo sandbox está roto y haga que lo arreglen. Le ahorrará mucho tiempo y esfuerzo, y si hay un error en la caja de arena, no será su culpa (bueno, al menos no del todo).

+2

eval = null; require = null; Después de aquí no hay más forma de ejecutar ambas funciones. No diré que hacer un sandbox es fácil, ya que tienes razón, olvida una cosa (como setTimers con evaluaciones implícitas) y ¡boom! Pero estás complicando demasiado las cosas. – axkibe

+0

Bueno, claro. El problema es que el OP busca una salida barata que simplemente no existe. La seguridad siempre es costosa y molesta. Su solución se ve bien hasta que aparece un cliente y exige poder llamar a 'eval()'. Algunos "tipos inteligentes" "arreglan" el problema al agregar 'var __ev = eval; eval = null; 'porque" nadie se dará cuenta de eso "(seguridad por oscuridad). –

+5

¿Por qué eval es realmente malo? El código evaluado no puede acceder requiere y procesa si está configurado como nulo o no definido primero. Entonces ... no entiendo por qué crees que el código debe estar preprogramado para ejecutarse en un entorno limitado. La caja de arena debe ser "justa" estricta con respecto al entorno al que puede acceder. – axkibe

1

Si puede pagar el rendimiento, puede ejecutar el JS en una máquina virtual desechable con los límites adecuados de CPU y memoria.

Por supuesto, entonces confía en la seguridad de la solución de VM. Al usarlo junto con un sandbox JS ordinario, tendrías dos niveles de seguridad.

Para una capa adicional, coloque la caja de arena en una máquina física diferente a la de su aplicación principal.

1

Docker.io Es un chico nuevo impresionante en el bloque, que usa LXC sy CGroups para crear entornos aislados.

Aquí es una implementación de un online gist (similar a codepad.org) usando Docker y Go Lang

Esto sólo sirve para demostrar que se puede ejecutar de forma segura código no confiable escrito en muchos lenguajes de programación dentro Docker Containers, incluyendo node.js

+0

¡Gracias por compartir! Incluí la esencia que mencionaste en una gema de Ruby aquí: https://github.com/vaharoni/trusted-sandbox. Permite ejecutar código no confiable con Ruby, aunque se puede usar fácilmente para ejecutar JS usando el ruby ​​racer. Permite establecer cuotas de disco, limitar la memoria, compartir CPU, etc. – AmitA

+3

Docker no está diseñado como una herramienta de aislamiento. Está diseñado para facilitar el "empaquetado" y la distribución de la aplicación. Eso no quiere decir que sea totalmente inseguro (ver [aquí] (https://blog.docker.com/2013/08/containers-docker-how-secure-are-they/) por ejemplo), sino más bien que la seguridad no es parte de sus principios de diseño, y es simplemente incorrecto indicarlo como una "herramienta sanboxing". Según mi leal saber y entender, la forma estándar de proteger el código que no es de confianza es usando Máquinas Virtuales o, para los idiomas interpretados que lo soportan (por ejemplo, pypy), la "opción de espacio aislado" del intérprete ... – mac

0

Me enfrento a un problema similar en este momento y estoy leyendo solo cosas malas sobre el módulo sandbox.

Si no necesita nada específico para el entorno del nodo, creo que lo mejor será usar un navegador sin cabeza, como PhantomJS o Chimera, para utilizarlo como entorno de recinto de seguridad.

7

Recientemente he creado una biblioteca para el espacio aislado del código no confiable, parece ajustarse a las demandas (ejecuta un código en un proceso restringido en el caso de Node.js, y en un Worker dentro de un iframe de espacio aislado para un web- navegador):

https://github.com/asvd/jailed

Hay una oportunidad para exportar el conjunto dado de métodos de la aplicación principal en el entorno limitado proporcionando así cualquier API personalizada y un conjunto de privilliges (esa característica era en realidad la razón por la que decidí hacer una biblioteca desde cero). Las cosas mencionadas de matemáticas, expresiones regulares y cadenas son proporcionadas por el propio JavaScript, cualquier elemento adicional puede exportarse explícitamente desde el exterior (como una función para comunicarse con la aplicación principal).

0

Sabemos que es bastante tarde para responder a la pregunta, supongo que la siguiente herramienta puede ser un valor agregado que no se menciona en las respuestas/comentarios anteriores.

Intentando implementar un caso de uso similar. Después de haber revisado los recursos web, https://www.npmjs.com/package/vm2 parece estar manejando el entorno de la zona de pruebas (nodejs) bastante bien.

Es más o menos satisface las características sandboxing como la restricción del acceso a la orden interna o módulos externos, intercambios de datos entre caja de arena, etc.

0

Una respuesta tardía pero quizás una idea interesante.

análisis de código estático =>manipulación AST =>Código generar

  1. análisis estático analizará la AST del código fuente. AST proporciona una estructura de datos común que nos permite recorrer y modificar el código fuente.
  2. A través de manipulaciones AST, podemos encontrar todas las referencias de identificador a cualquier variable sensible en los ámbitos externos. Si necesitamos , podemos volver a declararlos e inicializarlos al comienzo del cuerpo de la función , para sobrescribirlos. Por lo tanto, las referencias desde el interior hacia el exterior están bajo control.
  3. Generar códigos de AST también es fácil.

Por ejemplo, una función es como se muestra a continuación:

function() { 
    a = 1; 
    window.b = 1; 
    eval('window.c()'); 
} 

El análisis estático basado en el código JS analizador nos permite insertar instrucciones de declaración de variables antes de que el cuerpo de la función original:

function() { 
    var a, window = {}, eval = function() {}; // variable overwriting 
    a = 1; 
    window.b = 1; 
    eval('window.c()'); 
} 

Eso es.

Se deben considerar más sobrescrituras, como eval(), new Function() y otros objetos globales o API. Y las advertencias durante el análisis deberían estar bien organizadas e informadas.

Algunos trabajos relacionados en orden:

  • esprima, ECMAScript análisis de la infraestructura para el análisis de usos múltiples.
  • estraverse, ECMAScript JS AST funciones transversales.
  • escope, analizador de alcance ECMAScript.
  • escodegen, generador de código ECMAScript.

Mi práctica basada en lo anterior es function-sandbox.

Cuestiones relacionadas