Determina el tipo de archivo y genera nombres únicos en tu backend con Python

2 minutos

Python

Cuando desarrollas un backend, una de las tareas más triviales, y a menudo subestimadas, es recibir archivos enviados por usuarios. Es fácil asumir que si un archivo termina en .jpg es una imagen JPEG… pero esta suposición es de ser ingenuo.

Un archivo puede tener cualquier nombre o extensión sin que eso cambie su contenido. Por ejemplo, un usuario podría renombrar cualquier archivo .exe malicioso a imagen-sin-virus.jpg e intentar subirlo a tu servidor. Muy problemático.

Por eso, en este artículo te voy a mostrar cómo implementar una tarea básica pero fundamental en cualquier backend Python que acepte archivos: detectar el tipo real de un archivo a partir de su contenido, y además, asignarle un nombre único para evitar colisiones o problemas de seguridad.

Primero necesitaremos instalar la librería python-magic, que nos ayudará a determinar el tipo de archivo a partir de su mimetype. Esta librería es una interfaz de Python para la biblioteca libmagic, que se utiliza para identificar el tipo a partir de su contenido.

pip install python-magic

Para el ejemplo, vamos a crear un archivo temporal y escribirle algo de texto.

import tempfile

# 'delete' se utiliza para eliminar el archivo temporal después de su uso
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.write(b'Hello World')

El siguiente paso es determinar el tipo de archivo. Para ello, utilizaremos la función from_file de la librería magic, que nos devolverá el mimetype del archivo.

import magic
mime_type = magic.from_file(temp_file.name, mime=True)

Ahora ya podemos obtener la extensión usando la función guess_extension de la librería mimetypes..

from mimetypes import guess_extension

extension = guess_extension(mime_type)

Después, para asegurarnos de que el nombre del archivo sea único, utilizaremos la librería uuid para generar un identificador único.

import uuid

filename = f"{str(uuid.uuid4())}{extension}"

Ya podemos subir el archivo a nuestro almacenamiento o copiarlo a otro lugar. Nosotros lo vamos a copiar a /mnt/ejemplo/.

import shutil

shutil.copy(temp_file.name, f"/mnt/ejemplo/{filename}")

Finalmente, no olvides cerrar el archivo temporal para liberar recursos.

temp_file.close()

Todo junto sería algo así:

import tempfile
import uuid
from mimetypes import guess_extension
import magic
import shutil

temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.write(b'Hello World')
mime_type = magic.from_file(temp_file.name, mime=True)
extension = guess_extension(mime_type)
filename = f"{str(uuid.uuid4())}{extension}"
shutil.copy(temp_file.name, f"/mnt/ejemplo/{filename}")
temp_file.close()

Conclusión

Una de las reglas elementales de un backend es nunca fiarse de los datos u archivos que envíen los usuarios. En muy pocas líneas hemos asegurado que el archivo que subimos tiene la extensión correcta y además tenga un nombre único que mejora su seguridad. Si utilizas Django o similares, ya incorporarán la funcionalidad de evitar colisiones, pero no esta de más tener un sistema de nombres únicos.

Recuerda, este tipo de validación es crítica en APIs REST, microservicios o aplicaciones donde los usuarios suben archivos. ¡No olvides implementarlo!

Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional.

Atribución/Reconocimiento-NoComercial-SinDerivados 4.0 Internacional

¿Me invitas a un café? ☕

Puedes hacerlo usando el terminal.

ssh customer@andros.dev -p 5555

Comentarios

{{ comments.length }} comentarios

Nuevo comentario

Nueva replica  {{ formatEllipsisAuthor(replyComment.author) }}

Acepto la política de Protección de Datos.

Escribe el primer comentario

Tal vez también te interese...