personalizados framework formularios ejemplos avanzados python django security file-upload

python - framework - Validar archivos cargados en Django



formularios personalizados django (6)

''usuarios de confianza'' es un término subjetivo. ¿Son personas que conoces en persona o solo alguien que ha creado una cuenta en tu aplicación? No dé acceso a su sistema de archivos a personas que no conoce en persona.

En cualquier caso, dar la capacidad a alguien para subir un archivo es un poco peligroso y creo que debe evitarse. La semana pasada me enfrentaba a un problema similar con la carga automática del código html y decidí guardarlo en la base de datos. Creo que en la mayoría de los casos, puede usar la base de datos en lugar del sistema de archivos.

Un problema con la validación es que tendrá que escribir un nuevo validador para cualquier tipo de archivo. Puede ser una limitación en el futuro y una gran tarea en algunos casos.

Por lo tanto, recomendaría reconsiderar un diseño basado en la base de datos.

Una aplicación de Django en la que estoy trabajando tiene un modelo de Event . Un Event puede tener fotos asociadas, archivos html estáticos y archivos pdf.

Me gustaría permitir que los usuarios de confianza carguen estos archivos, pero desconfío de la seguridad, especialmente de haber leído lo siguiente en los documentos de Django (enlace).

Tenga en cuenta que siempre que trabaje con archivos cargados, debe prestar mucha atención a dónde los está cargando y qué tipo de archivos son, para evitar agujeros de seguridad. Valide todos los archivos cargados para asegurarse de que los archivos son lo que usted cree que son. Por ejemplo, si deja ciegamente que alguien cargue archivos, sin validación, a un directorio que esté dentro de la raíz del documento del servidor web, entonces alguien podría cargar un script CGI o PHP y ejecutar ese script visitando su URL en su sitio. No permitas eso.

¿Cómo puedo validar los diferentes tipos de archivos? Me interesaría escuchar la experiencia de alguien al lidiar con este tipo de cosas, o enlaces para leer más. Tengo la corazonada de que los archivos html pueden ser demasiado arriesgados, en cuyo caso restringiré los permisos de carga al administrador.


Esto es un poco específico para su entorno de alojamiento, pero esto es lo que hago:

Sirva todo el contenido subido por el usuario con Nginx en lugar de apache, y publíquelo como contenido estático (no ejecutará ninguno de los php o cgi, incluso si los usuarios lo cargan)


Lo primero que desea hacer con el contenido cargado es almacenarlo en un directorio al que no se puede acceder directamente para descargarlo. Si su aplicación existe en ~/www/ considere poner sus datos en ''~ / data / `.

En segundo lugar, debe determinar qué tipo de archivo subió el usuario y luego crear reglas para cada tipo de archivo.

No puede confiar en el archivo basado en la extensión, por lo tanto, use algo como Fileinfo . Luego, para cada tipo de mimo, crea un validador. ImageMagick puede validar archivos de imagen. Para mayor seguridad, puede que tenga que ejecutar un escáner de virus sobre archivos como archivos PDF y flash. Para html, es posible que desee considerar el límite para un subconjunto de etiquetas.

No puedo encontrar un equivalente de Python del módulo Fileinfo , aunque siempre es posible ejecutar /usr/bin/file -i . La mayoría del sistema que permite cargas y luego crea un nombre de contenido o ID. Luego usan mod_rewrite para analizar la URL y encontrar el contenido en el disco. Una vez que se encuentra el contenido, se devuelve al usuario usando sendfile o algo similar. Por ejemplo, hasta que se apruebe el contenido, tal vez solo el usuario que lo subió pueda verlo.


Para las imágenes, es posible que solo pueda utilizar Python Imaging Library (PIL).

Image.open(filepath)

Si el archivo no es una imagen, se lanzará una excepción. Soy bastante nuevo en Python / Django por lo que alguien más podría tener una mejor manera de validar imágenes.


Todas las respuestas se centran en la validación de archivos. Esto es casi imposible.

Los desarrolladores de Django no le piden que valide si los archivos se pueden ejecutar como archivos cgi. Simplemente te están diciendo que no los pongas en un lugar donde serán ejecutados.

Deberías poner todo el material de Django en un directorio especialmente Django. Ese directorio de código Django no debe contener contenido estático. No coloque archivos de usuario en el repositorio de origen de Django.

Si está utilizando Apache2, consulte el tutorial cgi básico: http://httpd.apache.org/docs/2.0/howto/cgi.html

Apache2 puede configurarse para ejecutar cualquier archivo en la carpeta ScriptAlias . No coloque archivos de usuario en /cgi-bin/ o /usr/local/apache2/cgi-bin/ folders.

Apache2 puede configurarse para archivos cgi del servidor, dependiendo de la AddHandler cgi-script . No permita que los usuarios envíen archivos con extensiones como .cgi o .pl .

Sin embargo, debe desinfectar los archivos enviados por el usuario para que se puedan ejecutar de forma segura en las máquinas de otros clientes . El HTML enviado no es seguro para otros usuarios. No dañará tu servidor. Tu servidor simplemente lo escupirá a quien lo solicite. Obtenga un sanitizador HTML.

Además, SVG puede ser inseguro . Ha tenido errores en el pasado. SVG es un documento XML con javascript, por lo que puede ser malicioso.

PDF es ... complicado. Podría convertirlo en una imagen (si realmente tenía que hacerlo), o proporcionar una vista previa de la imagen (y permitir que los usuarios descarguen bajo su propio riesgo), pero sería un dolor para las personas que intentan usarlo.

Considere una lista blanca de archivos que están bien. Un virus incrustado en un archivo gif, jpeg o png se verá como una imagen dañada (o no se puede mostrar). Si quieres ser paranoico, conviértalos a un formato estándar usando PIL (hey, también puedes consultar tamaños). El HTML desinfectado debería estar bien (eliminar las etiquetas de secuencia de comandos no es ciencia de cohetes). Si la sanitización es ciclos de succión (o si solo tienes cuidado), podrías ponerlo en un servidor por separado, supongo.