Construir

Subir archivos en Flask de forma segura

Cómo recibir archivos que sube el usuario en Flask: el formulario, guardar el archivo, y las validaciones de seguridad que evitan que alguien te suba algo peligroso.

Permitir que un usuario suba un archivo —una foto de perfil, un PDF, un documento— es una necesidad común en casi cualquier app. Y es también uno de los puntos donde más agujeros de seguridad se abren si se hace a la ligera. Aquí lo montamos completo y seguro en Flask.

El formulario HTML

Un detalle que rompe el subir archivos antes de empezar: el formulario debe llevar enctype="multipart/form-data". Sin eso, el archivo no llega al servidor.

<form action="/subir" method="post" enctype="multipart/form-data">
  <input type="file" name="archivo">
  <button type="submit">Subir</button>
</form>

Es el error número uno: el formulario parece correcto pero sin ese enctype el servidor recibe el nombre del archivo, no el archivo. Que no se te olvide.

Recibir y guardar el archivo

import os
from flask import Flask, request, redirect, url_for, flash
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.secret_key = "clave-secreta"
app.config["CARPETA_SUBIDAS"] = "subidas"

@app.route("/subir", methods=["POST"])
def subir():
    if "archivo" not in request.files:
        flash("No se envió ningún archivo")
        return redirect(url_for("index"))

    archivo = request.files["archivo"]

    if archivo.filename == "":
        flash("No se seleccionó ningún archivo")
        return redirect(url_for("index"))

    nombre = secure_filename(archivo.filename)
    ruta = os.path.join(app.config["CARPETA_SUBIDAS"], nombre)
    archivo.save(ruta)

    flash("Archivo subido correctamente")
    return redirect(url_for("index"))

La pieza de seguridad más importante aquí es secure_filename. Nunca guardes un archivo con el nombre tal cual lo manda el usuario. Un nombre malicioso como ../../config.py podría escribir el archivo fuera de tu carpeta y sobrescribir cosas del sistema. secure_filename limpia el nombre, quitando barras, puntos peligrosos y caracteres raros, dejando algo seguro para el disco. Es imprescindible, no opcional.

Las dos comprobaciones anteriores ("archivo" not in request.files y filename == "") atrapan los casos de formulario enviado sin archivo, que si no revientan el código.

Validar el tipo de archivo

No querrás que suban cualquier cosa. Si esperas imágenes, acepta solo imágenes. Se filtra por la extensión:

EXTENSIONES_OK = {"png", "jpg", "jpeg", "gif", "pdf"}

def extension_permitida(nombre):
    return "." in nombre and nombre.rsplit(".", 1)[1].lower() in EXTENSIONES_OK

Y lo usas antes de guardar:

    if not extension_permitida(archivo.filename):
        flash("Tipo de archivo no permitido")
        return redirect(url_for("index"))

Filtrar extensiones evita que alguien suba, por ejemplo, un archivo ejecutable disfrazado. No es una barrera perfecta por sí sola, pero es la primera línea de defensa y siempre debe estar.

Limitar el tamaño

Sin un límite, alguien podría subir un archivo enorme y llenarte el disco o tumbar el servidor. Flask lo controla con una línea de configuración:

# Máximo 5 MB por subida
app.config["MAX_CONTENT_LENGTH"] = 5 * 1024 * 1024

Si el archivo supera ese tamaño, Flask rechaza la petición automáticamente antes de procesarla. Ajusta el número a lo que tenga sentido para tu caso.

Preparar la carpeta de destino

Un detalle práctico: la carpeta donde guardas los archivos debe existir antes, o el save() falla. Créala al arrancar la app:

os.makedirs(app.config["CARPETA_SUBIDAS"], exist_ok=True)

El exist_ok=True evita que dé error si la carpeta ya existe.

Resumen de las defensas

Subir archivos de forma segura se reduce a cuatro capas, y conviene tenerlas todas:

  • secure_filename para limpiar el nombre — contra rutas maliciosas.
  • Validar la extensión — contra tipos de archivo peligrosos.
  • MAX_CONTENT_LENGTH para limitar el tamaño — contra saturación.
  • Guardar en una carpeta dedicada, nunca dentro del código de la app.

Con esas cuatro tienes una subida de archivos lista para uso real. A partir de aquí puedes añadir cosas como renombrar los archivos con un identificador único para evitar que dos usuarios con el mismo nombre de archivo se pisen, pero eso es una mejora sobre una base que ya es sólida.


¿Necesitas subir varios archivos a la vez, o guardarlos en la nube en vez de en disco? Escríbeme desde contacto y lo vemos.

← Más de Construir