Tengo un proyecto en el que necesito permitir a los usuarios ejecutar código python arbitrario y no confiable ( un poco como este ) en mi servidor. Soy bastante nuevo en Python y me gustaría evitar cometer errores que introduzcan agujeros de seguridad u otras vulnerabilidades en el sistema. ¿Hay algunas mejores prácticas disponibles, lecturas recomendadas u otros consejos que pueda darme para que mi servicio sea utilizable pero no abusivo?
Esto es lo que he considerado hasta ahora:
- Eliminar
__builtins__
delexec
contexto para prohibir el uso de paquetes potencialmente peligrosos comoos
. Los usuarios solo podrán usar los paquetes que les proporcione. - Use hilos para hacer cumplir un tiempo de espera razonable.
- Me gustaría limitar la cantidad total de memoria que se puede asignar dentro del
exec
contexto, pero no estoy seguro de si es posible.
Hay algunas alternativas a una escalera exec
, pero no estoy seguro de cuál de ellas sería útil aquí:
- Usar un
ast.NodeVisitor
para detectar cualquier intento de acceder a objetos inseguros. ¿Pero qué objetos debería prohibir? - Buscando cualquier subrayado doble en la entrada. (menos elegante que la opción anterior).
- Usando
PyPy
o algo similar a sandbox el código.
NOTA: Soy consciente de que hay al menos un intérprete basado en JavaScript. Eso no funcionará en mi escenario.
python
security
web-services
pswg
fuente
fuente
Respuestas:
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:
Ned Batchelder comienza con una demostración de lo peligroso
eval()
que es realmente ;eval()
a menudo se usa para ejecutar expresiones de Python; como una caja de arena primitiva e ingenua para frases sencillas.Luego continuó tratando de aplicar los mismos principios a Python 3 , y finalmente logró romper con algunos consejos útiles.
Pierre Bourdon utiliza técnicas similares para hackear un sistema python en un hack-a-thon
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 localos
en el espacio de nombres de su módulo que se refiere alos
módulo. Esto puede llevar a un atacante determinado a módulos que pueden ayudarlo a salir de la caja de arena. Elpickle
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 alpickle
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.
fuente
TL; DR Utilice un chroot / jail y ejecútelo como un usuario personalizado sin ningún privilegio.
La mejor práctica para ejecutar código no confiable es segregarlo a través de un sandbox del sistema . Para mayor seguridad:
También sigue las prácticas estándar para ejecutar cosas de forma segura en un chroot. Puede reconstruir el sistema de archivos del chroot con cada llamada, también es particularmente paranoico. Por lo general, solo hace que el usuario no pueda realizar modificaciones en el sistema de archivos en el que se ejecuta chroot.
fuente
No hay forma de que pueda hacer esto de manera segura.
Si quisieras hacer algo como esto de manera segura, tendrías que comenzar por tener tu propia implementación de python que se ejecute en un entorno completamente controlado, preferiblemente en el navegador de los usuarios en lugar de en tu sistema. Puede comenzar con Jython (python para java) y empaquetarlo como un applet de java. Dado que se estaría ejecutando en el sandbox de Java, en la máquina del usuario, su sistema sería razonablemente seguro.
fuente
Como dijo Martijn anteriormente, esto es muy, muy difícil en Python. Sin rodeos porque Python es tan introspectable, no creo que sea posible limitando las características del lenguaje. Y si obtiene un sandbox que funcione para una versión de Python, existe la posibilidad de que la próxima versión lo rompa.
Echaría un vistazo a PyPy en lugar de CPython estándar. En resumen, es una implementación alternativa compatible de Python. Tiene varias ventajas y características distintas, y una de ellas es el sandboxing mediante la sustitución de llamadas del sistema en lugar de limitar las características del lenguaje.
fuente
Mientras el rendimiento no sea enormemente importante para usted, siempre puede ejecutarlo en Brython, que lo coloca efectivamente en el entorno limitado de JavaScript
fuente