El sandboxing de Python es difícil . Python es inherentemente introspectable, en múltiples niveles.
Esto también significa que puede encontrar los métodos de fábrica para tipos específicos de esos tipos y construir nuevos objetos de bajo nivel, que el intérprete ejecutará directamente sin limitación.
Estos son algunos ejemplos de cómo encontrar formas creativas de salir de los entornos limitados de Python:
La idea básica es siempre encontrar una manera de crear tipos básicos de Python; funciones y clases y salir del shell haciendo que el intérprete de Python ejecute bytecode arbitrario (¡sin marcar!).
Lo mismo y más se aplica a la exec
declaración ( exec()
función en Python 3).
Entonces tu quieres:
Controle estrictamente la compilación de bytes del código de Python, o al menos procese el código de bytes para eliminar cualquier acceso a los nombres que comienzan con guiones bajos.
Esto requiere un conocimiento profundo de cómo funciona el intérprete de Python y cómo está estructurado el bytecode de Python. Los objetos de código están anidados; el código de bytes de un módulo solo cubre el nivel superior de las declaraciones, cada función y clase consta de su propia secuencia de código de bytes más metadatos, que contienen otros objetos de código de bytes para funciones y clases anidadas, por ejemplo.
Debe incluir en la lista blanca los módulos que se pueden usar. Cuidadosamente.
Un módulo de Python contiene referencias a otros módulos. Si importa os
, hay un nombre local os
en el espacio de nombres de su módulo que se refiere al os
módulo. Esto puede llevar a un atacante determinado a módulos que pueden ayudarlo a salir de la caja de arena. El pickle
módulo, por ejemplo, le permite cargar objetos de código arbitrario, por ejemplo, por lo que si alguna ruta a través de los módulos incluidos en la lista blanca conduce al pickle
módulo, aún tiene un problema.
Debe limitar estrictamente las cuotas de tiempo. Incluso el código más castrado puede intentar ejecutarse para siempre, atando sus recursos.
Eche un vistazo a RestrictedPython , que intenta darle el estricto control de bytecode. RestrictedPython
transforma el código de Python en algo que le permite controlar qué nombres, módulos y objetos están permitidos en Python 2.3 a 2.7.
Si RestrictedPython
es lo suficientemente seguro para sus propósitos depende de las políticas que implemente. No permitir el acceso a nombres que comienzan con un guión bajo y estrictamente incluir en la lista blanca los módulos sería un comienzo.
En mi opinión, la única opción verdaderamente robusta es usar una máquina virtual separada, una sin acceso a la red al mundo exterior que destruyes después de cada ejecución. Cada nuevo script recibe una nueva VM en su lugar. De esa manera, incluso si el código logra salir de su entorno limitado de Python (lo cual no es improbable), todo el atacante tiene acceso de corta duración y sin valor.