FixVibe

// docs / baas security / supabase storage

Lista de comprobación de seguranza de buckets de almacenamento de Supabase: 22 elementos

Supabase Storage é unha capa fina sobre un bucket compatible con S3 máis o mesmo modelo de seguranza a nivel de fila que a base de datos. Iso significa que as mesmas trampas RLS que afectan as táboas afectan o acceso a ficheiros — e algunhas específicas de almacenamento que aparecen cando as ferramentas de codificación con IA configuran cargas. Esta lista contén 22 elementos en cinco seccións: configuración de buckets, políticas RLS, validación de cargas, URLs asinados e hixiene operacional. Cada elemento é verificábel en menos de 15 minutos.

Cada elemento de abaixo é esencial. Para a mecánica subxacente de RLS, mira Escáner de RLS de Supabase. Para a clase de exposición de claves adxacente ao almacenamento, mira Clave de rol de servizo de Supabase exposta en JavaScript.

Configuración do bucket

Comeza cos valores por defecto correctos. Un bucket mal configurado filtra ficheiros, esté ou non correcta a túa RLS.

  1. Por defecto cada bucket debe ser privado. No Panel de Supabase → Almacenamento → Buckets, pon o toggle de Bucket público a apagado a menos que teñas un motivo explícito (activos de marketing, avatares públicos sen PII). Os buckets públicos saltan RLS para operacións de lectura — calquera co nome do bucket pode listar e descargar.
  2. Pon un límite duro de tamaño de ficheiro en cada bucket. Panel → Configuración do bucket → Límite de tamaño de ficheiro. 50 MB é un valor por defecto sensato para cargas de usuario; aumenta deliberadamente para casos de vídeo / ficheiros grandes. Sen límite, unha única carga maliciosa pode esgotar a túa cota de almacenamento ou o teu ancho de banda mensual.
  3. Restrinxe os tipos MIME permitidos por bucket. Lista de tipos MIME permitidos — lista branca explícita, non lista negra. image/jpeg, image/png, image/webp para buckets só de imaxes. Nunca permitas text/html, application/javascript ou image/svg+xml nun bucket de contido de usuario — execútanse no navegador cando se serven vía URL asinado.
  4. Usa un bucket por tipo de contido, non un bucket compartido. A granularidade que tes é a configuración por bucket (tamaño, tipos MIME, políticas RLS). Un bucket user-avatars, un bucket document-uploads e un bucket public-assets son máis doados de bloquear que un bucket mixto.
  5. Verifica a configuración CORS se as cargas son do frontend. Se os usuarios cargan directamente desde o navegador a un URL asinado, o CORS do bucket debe listar a túa orixe de produción. * é aceptable só para buckets públicos — nunca para buckets que conteñan PII de usuario.

Políticas RLS en storage.objects

Supabase Storage almacena os metadatos de ficheiros na táboa storage.objects. RLS nesa táboa controla quen pode ler, cargar, actualizar ou eliminar ficheiros. Sen RLS, o flag público/privado do bucket é a túa única protección.

  1. Confirma que RLS está activado en storage.objects. SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; debe devolver true. Supabase actívao por defecto en proxectos novos; verifica que non se desactivase.
  2. Escribe unha política SELECT con ámbito a auth.uid() para buckets privados. CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]);. A convención é almacenar ficheiros baixo [user-id]/[filename] e usar storage.foldername() para extraer o propietario do camiño.
  3. Escribe unha política INSERT que impoña a mesma convención de camiño. CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. Sen WITH CHECK, un usuario autenticado pode cargar no cartafol doutro usuario.
  4. Engade políticas UPDATE e DELETE se a túa aplicación admite edicións ou eliminacións de ficheiros. Cada comando precisa da súa propia política. Saltar DELETE significa que os usuarios autenticados non poden eliminar os seus propios ficheiros; saltar UPDATE significa que as sobrescrituras de ficheiros fallan silenciosamente.
  5. Proba acceso entre usuarios en dúas sesións de navegador. Inicia sesión como Usuario A, carga un ficheiro, copia o camiño. Inicia sesión como Usuario B noutro navegador, tenta obter o ficheiro vía a API REST. A resposta debe ser 403 ou 404, nunca 200.
sql
-- Confirm RLS on storage.objects
SELECT rowsecurity
FROM   pg_tables
WHERE  schemaname = 'storage' AND tablename = 'objects';

-- SELECT policy: scope reads to the owning user's folder.
CREATE POLICY "users_read_own_files"
  ON storage.objects
  FOR SELECT
  USING (auth.uid()::text = (storage.foldername(name))[1]);

-- INSERT policy: enforce the [user-id]/[filename] path convention.
CREATE POLICY "users_upload_own"
  ON storage.objects
  FOR INSERT
  WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);

Validación de cargas

Valida cada carga no lado do servidor, mesmo cando o bucket teña restricións de MIME e tamaño. As ferramentas de codificación con IA xeran validación só no cliente por defecto; iso non protexe nada.

  1. Volve comprobar o tipo MIME no lado do servidor a partir dos bytes reais do ficheiro, non da cabeceira Content-Type. Usa unha biblioteca como file-type (Node) ou inspección de bytes máxicos. Un atacante pode declarar Content-Type: image/jpeg nun ficheiro que en realidade é unha carga útil políglota de HTML / JavaScript.
  2. Elimina os metadatos EXIF das imaxes cargadas. EXIF pode conter coordenadas GPS, números de serie do dispositivo e marcas de tempo. Usa sharp con .withMetadata(false) ou exif-parser para eliminalos antes de almacenar.
  3. Rexeita SVGs que conteñan etiquetas script ou manejadores onload. SVG é XML — e moitas aplicacións xeradas por IA permiten cargas SVG como "só unha imaxe". Usa DOMPurify no lado do servidor ou rexeita totalmente as cargas SVG.
  4. Usa nomes de ficheiro deterministas e non adivinables. Non preserves o nome de ficheiro orixinal. Usa un UUID ou un hash do contido do ficheiro. Os nomes orixinais filtran ("passport_scan_2024_01_15.jpg") e os nomes predicibles permiten enumeración.

URLs asinados

Os URLs asinados son como os clientes acceden a buckets privados. A expiración, o ámbito do bucket e o que se rexistra importan.

  1. Por defecto, expiración do URL asinado de 1 hora ou menos. O createSignedUrl(path, expiresIn) do SDK JS de Supabase recibe segundos. Nunca uses valores como 31536000 (un ano) — o URL convértese nunha ligazón semipública permanente.
  2. Nunca almacenes URLs asinados na túa base de datos. Xera novos no lado do servidor en cada solicitude. Un URL asinado almacenado cunha expiración de 1 ano que se filtra vía un volcado da base de datos concede acceso a longo prazo.
  3. Rexistra a xeración de URLs asinados, non só as cargas de ficheiros. Se sospeitas dun compromiso máis tarde, precisas saber quen xerou que URL e cando. Rexistra auth.uid() + bucket + camiño do obxecto + marca de tempo.
  4. Usa a opción downloadAs ao servir ficheiros cargados polo usuario. createSignedUrl(path, expiresIn, { download: '.jpg' }) forza unha cabeceira Content-Disposition: attachment para que o ficheiro se descargue en vez de renderizarse — derrota a clase de execución de HTML / SVG / HTML-en-PDF.

Hixiene operacional

A configuración do almacenamento desvíase co tempo. Estes catro elementos operacionais manteñen a superficie axustada.

  1. Audita os buckets trimestralmente. Panel → Almacenamento → Buckets. Confirma o estado público/privado e que as listas de tipos MIME coinciden co que a aplicación espera. Os buckets creados "temporalmente" convértense en permanentes se ninguén os elimina.
  2. Monitoriza as operacións de listaxe anónima. Os rexistros de almacenamento (Panel → Rexistros → Almacenamento) rexistran solicitudes LIST. Un pico de solicitudes de listaxe anónimas contra un bucket privado significa que alguén está sondándoo desde fóra.
  3. Pon unha política de retención para cargas efémeras. Os buckets temporais (vista previa de imaxes, cargas de borrador) deben auto-eliminarse despois de 24-72 horas vía unha función programada. A retención indefinida é unha responsabilidade baixo as obrigas de minimización de datos do RXPD / CCPA.
  4. Executa un escaneo de FixVibe mensualmente. A comprobación baas.supabase-storage-public sondea buckets que responden a GET + LIST anónimos. Engádense novos buckets; os antigos cambian de visibilidade — só o escaneo continuo capta a desviación.

Próximos pasos

Executa un escaneo de FixVibe contra o teu URL de produción — as listaxes de almacenamento anónimo aparecen baixo baas.supabase-storage-public. Empareja esta lista con Escáner de RLS de Supabase para a capa de táboas e con Clave de rol de servizo de Supabase exposta en JavaScript para a adxacencia de exposición de claves. Para configuracións incorrectas de almacenamento noutros provedores BaaS, mira Escáner de configuración incorrecta de BaaS.

// escanea a túa superficie baas

Atopa a táboa aberta antes de que outra persoa o faga.

Introduce un URL de produción. FixVibe enumera os provedores de BaaS cos que fala a túa aplicación, identifica os seus endpoints públicos e informa do que un cliente non autenticado pode ler ou escribir. Gratis, sen instalación, sen tarxeta.

  • Plan gratuíto — 3 escaneos ao mes, sen tarxeta de rexistro.
  • Identificación pasiva de BaaS — non se require verificación de dominio.
  • Supabase, Firebase, Clerk, Auth0, Appwrite e máis.
  • Prompts de corrección con IA en cada achado — pégaos de volta en Cursor / Claude Code.
Lista de comprobación de seguranza de buckets de almacenamento de Supabase: 22 elementos — Docs · FixVibe