Código de confianza suministrado por el usuario no confiable en una aplicación web

11

Estoy tratando de crear un juego de programación en el que los programas suministrados por el usuario compitan en simulaciones de batalla, para ser utilizados como una herramienta para enseñar y practicar la programación. (Probablemente será una simulación de robot por turnos, pero para los propósitos de esta pregunta, podría haber sido ajedrez o juego de damas). Un componente importante de la implementación de este juego será proporcionar un mecanismo para ejecutar los juegos generados por los usuarios. código contra los datos del juego para determinar los movimientos de su bot.

Sé que el consejo típico es: "Siempre que sea posible, no ejecute código que no sea de confianza", y entiendo de dónde proviene. En mi caso actual, sin embargo, sería la funcionalidad principal de la aplicación que me gustaría crear, si es posible. Sé que tendré que tomar algunas precauciones para garantizar que el código proporcionado por el usuario no cause daños. La configuración ideal, por lo que puedo decir, haría cumplir eso:

  • El código de usuario lee el estado del juego desde STDIN
  • El código de usuario escribe el movimiento generado a STDOUT
  • El código de usuario está aislado del sistema host
  • El código de usuario está aislado unos de otros
  • El código de usuario está limitado en los recursos que puede consumir (CPU, memoria, disco)
  • El código de usuario no puede acceder a la red

Mi caso de uso no parece único. En todo caso, me imagino que cualquiera de los siguientes tipos de aplicaciones tienen requisitos similares:

  • la mayoría de los juegos de programación
  • juez de programación competitiva en línea
  • "Prueba el lenguaje de programación X"
  • competiciones de juegos de inteligencia artificial

Sin embargo, miré a mi alrededor en Google, pero no pude encontrar ninguna implementación de referencia que pareciera confiable. La mayoría de los tipos de aplicaciones anteriores son de código cerrado, y quizás por una buena razón.

Dados los requisitos, me imagino que necesitaría algún tipo de solución de aislamiento / virtualización / contenedorización, aunque honestamente no estoy seguro de cuál proporcionaría las garantías necesarias.

¿Cuáles son las mejores prácticas actuales en relación con el sandbox para el código proporcionado por el usuario? ¿Alguien tiene alguna información o referencias a fuentes confiables?

    
pregunta Ming 07.07.2015 - 05:14
fuente

5 respuestas

2

Volviendo a esta pregunta con un poco de retraso ... Supongo que el código que recibe es ejecutado por el cliente en su intérprete de Javascript, y en algún momento se envía e interpreta en el servidor para su validación.

Tienes múltiples problemas:

  1. desea asegurarse de que el código ejecutado para un jugador no pueda afectar negativamente a otro jugador
  2. desea asegurarse de que el código que ejecuta no permita ninguna escalada de privilegios a nivel del sistema operativo
  3. bonificación opcional: desea saber cuándo algo salió mal durante la ejecución del código del cliente

entrada de desinfección

Lo primero es lo primero: recuerde incluir en la lista blanca las entradas que obtiene de sus clientes. Deben tener una longitud y formato conocidos. Utilice un formato independiente de la plataforma para almacenar los datos que recibe, que especifican las longitudes y los tipos de todas las variables intercambiadas.

Aislar clientes

Luego debe asegurarse de que el cómputo de cualquier entrada pueda llevar a un resultado correcto, o que el cómputo falle sin afectar el sistema operativo u otros cómputos concurrentes. Esto significa que cada entrada se procesa en su propio hilo / proceso contenido. Podría hacer que su servidor web reenvíe la entrada a un demonio personalizado que genere un proceso de espacio aislado en el servidor por cliente y lo alimente con la entrada.

También puede usar algo como Cuña para compartimentar de forma directa y segura una sola servidor. Capsicum también podría ser una opción.

Incluso si elige usar un solo intérprete de Javascript para ejecutar el código JS escrito por sus clientes que no son de confianza, pronto tendrá las herramientas adecuadas para garantizar el aislamiento ya que COWL (un mecanismo de confinamiento que implementa con éxito la no interferencia para el código JS) está siendo estandarizado por el W3C.

Proteger el sistema operativo

En cualquier dirección, simplemente debe asegurarse de que los procesos que ejecutan su código son:

  • no ejecutado por root / con capacidades equivalentes a root
  • contenido dentro de un cgroup para habilitar las limitaciones de QoS en el ancho de banda de la CPU, la memoria, el disco y la red (creo que este último puede requerir espacios de nombres de red)
  • contenido dentro de un espacio de nombres de usuario

Saber que el resultado del cálculo es confiable

Tome un curso sobre seguridad basada en el idioma :-) Este es un objetivo muy difícil por lo general y requiere muchas suposiciones sobre el idioma y las propiedades de seguridad que desea garantizar.

¡Buena suerte!

    
respondido por el Steve DL 04.11.2015 - 18:21
fuente
0

Dado que la mayoría (más del 50%) de las aplicaciones web están integradas en Java, asumo que vas a implementar una aplicación web basada en Java.

Puede tomar archivos jar de los estudiantes participantes y, en primer lugar, desinfectarlos para que el malware más conocido elimine las fuentes de problemas más obvias.

Puede definir una clase de interfaz en la que se debe crear una instancia de todo el código enviado. Esto podría restringir el conjunto de funciones expuestas al entorno del juego, por ejemplo: getGameState (), CalculateMove (), etc. El motor del juego ejecutaría estos métodos para cada participante en la secuencia requerida según las reglas del juego.

Debe restringir el código definiendo un SecurityManager personalizado con un ClassLoader específico para restringir las acciones en el dominio de seguridad del participante. Esto le permitirá aplicar una política de seguridad personalizada de una manera muy flexible.

Puede considerar aplicar los siguientes permisos de acceso:

  1. Desactive todos los accesos al sistema de archivos.
  2. Permitir el acceso reflexivo solo a sus propias clases.
  3. Denegar llamadas peligrosas al sistema como load (), loadLibrary (), gc (), setSecurityManager (), console (), etc.
  4. Deshabilitar todo el acceso a la red.
  5. Deshabilitar la creación de nuevos subprocesos.

Además, considere monitorear la asignación de memoria y el uso del procesador para el código ejecutado. Podría extender esto a todos los recursos disponibles en el servidor de aplicaciones.

Para disuadir a los estudiantes maliciosos o descuidados, puede publicar métricas como el consumo de memoria y la utilización del procesador para sus envíos. También puede penalizar a los consumidores de recursos pesados al reducir su clasificación para que se aliente a los estudiantes a ser más cuidadosos y económicos en el uso de los recursos informáticos.

    
respondido por el Sandeep S. Sandhu 16.08.2016 - 17:53
fuente
0

¿Ha considerado usar JavaScript y Caja de Google ?

  

El Compilador de Caja es una herramienta para hacer que los HTML, CSS y JavaScript de terceros se puedan incrustar en su sitio web. Permite una interacción rica entre la página de incrustación y las aplicaciones integradas. Caja utiliza un modelo de seguridad de capacidad de objetos para permitir una amplia gama de políticas de seguridad flexibles, de modo que su sitio web pueda controlar efectivamente lo que el código de terceros integrado puede hacer con los datos del usuario.      

El Compilador de Caja es compatible con la mayoría de HTML y CSS y la versión de JavaScript "modo estricto" recientemente estandarizada, incluso en los navegadores más antiguos que no admiten el modo estricto. Permite que el código de terceros utilice nuevas funciones de JavaScript en navegadores antiguos que no las admiten.

    
respondido por el ErikE 21.08.2016 - 05:23
fuente
-2

Muchas personas están diciendo que desinfecten la información ( gran respuesta aquí ), pero un gran enfoque para esto sería lista blanca / lista negra y hacer coincidencias de cadena .

Lista negra:
Si alguna parte de la cadena contiene algo conocido como incorrecto y se compara con una lista que se puede actualizar de forma remota (por ejemplo, un json de cadenas conocidas en comandos incorrectos que se pueden actualizar desde un repositorio y agregarse también a lo largo del tiempo), entonces solo puede coincidir con eso, y si cumple con los requisitos de seguridad, siga adelante y ejecútelo.

Lista blanca:
Esto incluso trae la funcionalidad adicional de usar la concordancia de cadenas para invocar rutinas predefinidas que usted mismo ha escrito para crear su propio conjunto de instrucciones simplificadas para que los jugadores las usen, de modo que ni siquiera pueden intentar hacer nada malo. Ahora todo lo que tiene que hacer es escanear y ver que solo contiene sus patrones aprobados previamente (nuevamente, se pueden actualizar de forma remota desde algún tipo de repositorio) y si contiene algo más, simplemente envíe un error que indique el código incorrecto.

Drawbacks:

  • Mantener listas de manera oportuna
  • No lo hagas muy simple
  • La mayor parte del tiempo y la energía se gastarán procesando los comandos

Adventages:

  • USTED lo definió
  • Puede enviar la entrada para que se limpie en otra máquina (si la máquina responde de manera correcta y con formato previo [recuento de caracteres explícitos, tamaño de paquete y patrón], confíe en la entrada y ejecútela)
  • Puedes hacer el juego mucho más simple

Entonces, mientras mantengas tu sistema seguro, la concordancia de cadenas podría hacer que sea más fácil mantenerte seguro ya que lo estás haciendo para sanear la entrada.

    
respondido por el Robert Mennell 02.05.2016 - 23:06
fuente
-3

Hay varios entornos limitados integrados en el software popular (motores antivirus, Adobe Reader, Java, etc.). Lo que todos estos programas tienen en común, es que todas sus cajas de arena ya estaban comprometidas en el pasado.

No basta con escribir solo sandbox, ya que alguien encontrará la manera de escapar.

Lo que debe hacer es escribir una implementación de máquina virtual completa. O simplemente es la pila de ejecución, ya que puede tomar un excelente intérprete de LUA para el análisis de lenguaje, la tokenización, etc.

Por supuesto, el propósito de escribir su propia pila de ejecución de VM es permitir la ejecución totalmente controlada de los programas de usuario. Solo necesita un subconjunto de lenguaje LUA, por lo que debería ser fácil de ejecutar todo a la manera del controlador, utilizando variables locales, sin interacción de red / disco.

Aquí tienes un manual para el inicio:

enlace

¡Buena suerte!

    
respondido por el Tomasz Klim 07.07.2015 - 09:48
fuente

Lea otras preguntas en las etiquetas