En resumen
Un bucket público sirve todos sus archivos a cualquiera que tenga la URL, sin clave y sin inicio de sesión: sus políticas de storage no se consultan para las descargas. En mi stack local el mismo archivo de prueba devolvió 200 con su contenido desde un bucket público y 400 desde uno privado. Las subidas, los borrados y los movimientos siguen pasando por las políticas. Use buckets públicos para archivos que son públicos por naturaleza, como avatares e imágenes de artículos, y buckets privados con URL firmadas para todo lo demás.
Mi verificador de seguridad de Supabase gratuito tiene dos reglas sobre buckets: “Buckets de storage públicos” los lista para que confirme que cada uno debe ser público, y “Buckets públicos sin límites de subida” señala los buckets públicos sin límite de tamaño ni de tipo de archivo. Esto es lo que cambia realmente la marca de público.
¿Qué significa un bucket público en Supabase?
La guía de buckets de Supabase define dos modelos de acceso. En un bucket privado, toda operación, descargas incluidas, pasa por las políticas RLS de storage.objects; un archivo se lee con el token del usuario o con una URL firmada que caduca. En un bucket público, la obtención y el servicio de archivos se saltan el control de acceso, así que cualquiera con la URL puede leer el archivo. El control de acceso sigue aplicándose a subir, borrar, mover y copiar.
Los buckets son privados por defecto. Un bucket pasa a ser público cuando alguien marca la casilla en el Dashboard o lo crea con public: true, un atajo habitual cuando una imagen no carga.
¿Qué devolvió cada bucket en mi prueba?
En un stack local de Supabase (CLI 2.109.1) creé un bucket público y uno privado, subí el mismo archivo de texto pequeño a ambos con la secret key y luego lo pedí sin ninguna clave, como lo haría un desconocido con el enlace:
Petición de 2026/invoice-001.txt |
Bucket público | Bucket privado |
|---|---|---|
/storage/v1/object/public/…, sin clave |
200, contenido del archivo |
400, “Bucket not found” |
/storage/v1/object/authenticated/…, solo la publishable key |
200 |
400 |
El bucket privado responde como si no existiera, que es lo que se quiere. El público entrega el archivo a cualquiera que pueda adivinar o encontrar la ruta.
¿Por qué importa tanto la URL?
Un archivo público es tan secreto como su ruta. Las rutas suelen ser predecibles: un id de usuario, una fecha, un número de factura. También se filtran por el código fuente de las páginas, los enlaces compartidos, el historial del navegador y los logs. Una factura, el escaneo de un pasaporte o un contrato firmado en un bucket público está, en la práctica, publicado.
¿Cómo elegir y corregirlo?
- Bucket público: archivos pensados para todos, como avatares, fotos de producto e imágenes de blog. Fije en el bucket un límite de tamaño y los tipos MIME permitidos, para que la vía pública de subida que permiten sus políticas no sirva para alojar otra cosa.
- Bucket privado: documentos, exportaciones, facturas, todo lo personal. Descargue con la sesión del usuario o cree una URL firmada que caduque.
Para ver sus buckets y sus límites:
select id, public, file_size_limit, allowed_mime_types
from storage.buckets
order by public desc, id;
Un bucket privado también necesita políticas sobre storage.objects, que normalmente comprueban que la primera carpeta de la ruta sea el id del usuario o de la empresa. Tras mover un proyecto, cuente esas políticas: en una app fallaron todas las subidas porque la migración de políticas nunca se ejecutó, y lo conté en mi lista de seguridad para apps Lovable. A qué más puede llegar la publishable key está en Supabase anon key frente a service role key.