Problemas de seguridad con los scripts de Python del usuario

1

Estoy generando imágenes dinámicas en un servicio web. La configuración actual es:

  • solicitud image.py
  • image.py realiza una búsqueda en la base de datos para determinar qué datos usar para generar la imagen
  • image.py llama a un sub-script (dado por la base de datos; por ejemplo, cats.py ) para generar la imagen en particular

Así que image.py contiene código de envoltorio estándar, y cats.py dibuja gatos ( dogs.py naturalmente dibujaría perros). Me gustaría generalizar esta configuración para que los usuarios puedan proporcionar su propio código de trazado, sujeto a mis variables proporcionadas previamente, principalmente el lienzo de trazado y la biblioteca math .

Por supuesto, permitir que se carguen scripts genéricos de Python es un problema de seguridad sustancial. Me gustaría mantener mi servidor bajo mi control y evitar que se use para disparar el spam a través de Internet; administrar el servidor con bucles y grandes estructuras de datos también es una preocupación, pero sé que no hay mucho que hacer al respecto (¡por favor, demuéstreme que estoy equivocado!).

¿Serán suficientes las siguientes medidas para protegerse contra las formas más flagrantes de abuso?

  • Llame a image.py como usuario con permisos limitados (para evitar que los usuarios obtengan información crítica del servidor)
  • Deshabilite funciones clave como __import__ , eval , exec , etc., al establecerlas como None , para limitar las capacidades a un entorno controlado (para evitar que los usuarios importen bibliotecas de red y otras cosas con potencial desagradable)

Estoy destruyendo el objeto de la base de datos y todas las variables críticas antes de llamar a los scripts de usuarios potenciales. Un desafío es que estoy devolviendo errores de Python cuando existen, modificando el tipo de contenido del documento devuelto. Esto podría permitir la inspección de ciertas propiedades, pero también es necesario para permitir la depuración.

He encontrado estas preguntas relacionadas, pero no estoy seguro de que estén directamente relacionadas:

Actualización: veo por las pruebas que __import__ = None no desactiva la palabra clave import . Así que quizás este concepto no funcione.

    
pregunta kyle 02.06.2015 - 03:01
fuente

2 respuestas

4

Para abordar este problema desde un ángulo diferente, ¿qué hay de crear un idioma específico del dominio ?

¿Por qué les da a los usuarios la capacidad de hacer una gran cantidad de cosas que no quieren que ellos puedan hacer, y luego intentan hacer una caja de arena y contener el poder que les está dando? En su lugar, cree un lenguaje simple que solo pueda usarse para trazar, e interprételo con Python.

Para que puedas crear un DSL simple llamado "Plot" o algo así. La trama sería un lenguaje que permite a los usuarios describir sus estrategias de trazado. Por lo tanto, su archivo image.py cargaría cat.plot , que usted o un usuario podrían proporcionar.

Como se mencionó en los comentarios, la lista blanca de funciones es mucho mejor que la lista negra. No le dé a los usuarios más poder del que necesitan, es mejor no darle el poder en primer lugar que tratar de contenerlo.

    
respondido por el Nathan 02.06.2015 - 07:17
fuente
0

La respuesta de @Nathan es bastante precisa: las funciones de la lista negra dejan algunos agujeros de seguridad considerables que son fácilmente explotables (con algunos googlear). No tuve la suerte de seguir las diversas instrucciones para poner en funcionamiento el sandboxing de PyPy, y lo mismo con chroot o Jailkit.

En última instancia, hice mi propio uso de varias técnicas. Reconozco que esto es largo, pero estas instrucciones realmente me habrían ayudado.

  • Cree un usuario falso con (relativamente) pocos permisos, image-user
  • Cree una jaula chroot para image-user , más o menos de acuerdo con estos pasos
  • Deshabilite todos los accesos de red para image-user , excepto para localhost. Esto permite que las conexiones de base de datos pasen. Tenga en cuenta que iptables parece ahogarse cuando "localhost" está en la lista blanca, debe ser "127.0.0.1"; lo mismo ocurre con las conexiones MySQLdb en Python. El comando es iptables -A OUTPUT ! -d 127.0.0.1 -m owner image-user -j DROP
  • Establezca sshd_config para que el usuario inicie sesión en su cárcel, Match user image-user \n ChrootDirectory /path/to/jail
  • Deshabilitar las conexiones no locales para este usuario en ssh_config
  • Habilite la autenticación basada en clave para ssh para este usuario
  • En lugar de cargar directamente image.py a través del navegador, use un script de envoltura que cargue al usuario con permisos reducidos a través de ssh; Como no hay acceso a la red y el usuario se encuentra en una jaula chroot, image-user podría, en el peor de los casos, destruir su estructura chroot. Esto sería malo pero rápido de arreglar desde una copia de seguridad del sistema. El script de envoltorio es PHP y la llamada es shell_exec( 'ssh image-user@localhost python image.py --param1 value1 --param2 value2' )

(Espero poder ampliar esta respuesta, especialmente porque el hecho de tener un servidor con iptables realmente puede administrar un servidor; estoy configurando esta descripción general mientras los eventos están frescos en mi mente)

    
respondido por el kyle 04.06.2015 - 21:03
fuente

Lea otras preguntas en las etiquetas