FixVibe

// docs / baas security / supabase storage

Llista de comprovació de seguretat de contenidors de Supabase Storage: 22 punts

Supabase Storage és un embolcall prim sobre un contenidor compatible amb S3 més el mateix model de seguretat a nivell de fila que la base de dades. Això significa que els mateixos paranys de RLS que afecten les taules afecten l'accés als fitxers — i alguns específics de l'emmagatzematge que apareixen quan les eines de codificació amb IA configuren pujades. Aquesta llista són 22 punts repartits en cinc seccions: configuració del contenidor, polítiques RLS, validació de pujades, URLs signades i higiene operativa. Cadascun és verificable en menys de 15 minuts.

Cada punt de sota és essencial. Per a la mecànica subjacent de RLS, consulta Escàner de RLS de Supabase. Per a la classe d'exposició de claus adjacent a l'emmagatzematge, consulta Clau de rol de servei de Supabase exposada a JavaScript.

Configuració del contenidor

Comença amb els valors per defecte correctes. Un contenidor mal configurat filtra fitxers tant si el teu RLS és correcte com si no.

  1. Posa cada contenidor com a privat per defecte. Al panell de Supabase → Storage → Buckets, desactiva l'interruptor Public bucket tret que tinguis una raó explícita (actius de màrqueting, avatars públics sense PII). Els contenidors públics se salten RLS per a operacions de lectura — qualsevol amb el nom del contenidor pot llistar i descarregar.
  2. Estableix un límit dur de mida de fitxer a cada contenidor. Panell → Configuració del contenidor → Límit de mida de fitxer. 50 MB és un valor per defecte sensat per a pujades d'usuari; augmenta'l deliberadament per a casos d'ús de vídeo / fitxers grans. Sense límit, una sola pujada maliciosa pot exhaurir la teva quota d'emmagatzematge o el teu ample de banda mensual.
  3. Restringeix els tipus MIME permesos per contenidor. Llista de tipus MIME permesos — llista d'autoritzats explícita, no llista de bloqueig. image/jpeg, image/png, image/webp per a contenidors només d'imatges. No permetis mai text/html, application/javascript ni image/svg+xml en un contenidor de contingut d'usuari — s'executen al navegador quan es serveixen via URL signada.
  4. Fes servir un contenidor per tipus de contingut, no un contenidor compartit. La configuració per contenidor (mida, tipus MIME, polítiques RLS) és la granularitat que tens. Un contenidor user-avatars, un contenidor document-uploads i un contenidor public-assets són més fàcils de blindar que un sol contenidor barrejat.
  5. Verifica la configuració CORS si fas pujades des del frontend. Si els usuaris pugen directament des del navegador a una URL signada, el CORS del contenidor ha de llistar el teu origen de producció. * és acceptable només per a contenidors públics — mai per a contenidors que continguin PII d'usuari.

Polítiques RLS sobre storage.objects

Supabase Storage emmagatzema les metadades dels fitxers a la taula storage.objects. RLS sobre aquesta taula controla qui pot llegir, pujar, actualitzar o esborrar fitxers. Sense RLS, l'indicador públic/privat del contenidor és la teva única protecció.

  1. Confirma que RLS està habilitat a storage.objects. SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; ha de retornar true. Supabase l'habilita per defecte en projectes nous; verifica que no s'hagi deshabilitat.
  2. Escriu una política SELECT delimitada a auth.uid() per a contenidors privats. CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]);. La convenció és emmagatzemar els fitxers sota [user-id]/[filename] i fer servir storage.foldername() per extreure el propietari de la ruta.
  3. Escriu una política INSERT que apliqui la mateixa convenció de ruta. CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. Sense WITH CHECK, un usuari autenticat pot pujar a la carpeta d'un altre usuari.
  4. Afegeix polítiques UPDATE i DELETE si la teva aplicació permet editar o esborrar fitxers. Cada comanda necessita la seva pròpia política. Saltar-se DELETE significa que els usuaris autenticats no poden eliminar els seus propis fitxers; saltar-se UPDATE significa que les sobreescriptures de fitxers fallen en silenci.
  5. Prova l'accés entre usuaris en dues sessions de navegador. Inicia sessió com a Usuari A, puja un fitxer, copia la ruta. Inicia sessió com a Usuari B en un altre navegador, intenta obtenir el fitxer via l'API REST. La resposta ha de ser 403 o 404, mai 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ó de pujades

Valida cada pujada al servidor, fins i tot quan el contenidor té restriccions de MIME i mida. Les eines de codificació amb IA generen validació només-client per defecte; això no protegeix res.

  1. Torna a comprovar el tipus MIME al servidor des dels bytes reals del fitxer, no des de la capçalera Content-Type. Fes servir una biblioteca com file-type (Node) o sniffing de bytes màgics. Un atacant pot declarar Content-Type: image/jpeg en un fitxer que en realitat és un payload polyglot HTML / JavaScript.
  2. Elimina les metadades EXIF de les imatges pujades. EXIF pot contenir coordenades GPS, números de sèrie del dispositiu i marques temporals. Fes servir sharp amb .withMetadata(false) o exif-parser per netejar-les abans d'emmagatzemar.
  3. Rebutja SVGs que continguin etiquetes script o gestors onload. SVG és XML — i moltes aplicacions generades amb IA permeten pujades SVG com a "només una imatge". Fes servir DOMPurify al servidor o rebutja directament les pujades SVG.
  4. Fes servir noms de fitxer deterministes i impredictibles. No conservis el nom original del fitxer. Fes servir un UUID o un hash del contingut del fitxer. Els noms originals filtren ("passport_scan_2024_01_15.jpg") i els noms predictibles permeten l'enumeració.

URLs signades

Les URLs signades són com els clients accedeixen als contenidors privats. La caducitat, l'àmbit del contenidor i què es registra importen.

  1. Posa la caducitat de les URLs signades a 1 hora o menys per defecte. El createSignedUrl(path, expiresIn) del SDK de Supabase JS pren segons. No facis servir mai valors com 31536000 (un any) — l'URL es converteix en un enllaç semi-públic permanent.
  2. No emmagatzemis mai URLs signades a la teva base de dades. Genera'n de noves al servidor a cada sol·licitud. Una URL signada emmagatzemada amb una caducitat d'un any que es filtri via un bolcat de base de dades atorga accés a llarg termini.
  3. Registra la generació d'URLs signades, no només les pujades de fitxers. Si sospites d'una vulneració més endavant, necessites saber qui ha generat quina URL i quan. Registra auth.uid() + contenidor + ruta de l'objecte + marca temporal.
  4. Fes servir l'opció downloadAs quan serveixis fitxers pujats per usuaris. createSignedUrl(path, expiresIn, { download: '.jpg' }) força una capçalera Content-Disposition: attachment perquè el fitxer es descarregui en lloc de renderitzar-se — neutralitza la classe d'execució HTML / SVG / HTML-en-PDF.

Higiene operativa

La configuració de l'emmagatzematge deriva amb el temps. Aquests quatre punts operatius mantenen la superfície ajustada.

  1. Audita els contenidors trimestralment. Panell → Storage → Buckets. Confirma que l'estat públic/privat i les llistes de tipus MIME coincideixen amb el que espera l'aplicació. Els contenidors creats "temporalment" es tornen permanents si ningú els elimina.
  2. Monitoritza les operacions de llistat anònimes. Els registres d'emmagatzematge (Panell → Logs → Storage) registren les sol·licituds LIST. Un pic de sol·licituds de llistat anònimes contra un contenidor privat significa que algú l'està sondejant des de fora.
  3. Estableix una política de retenció per a pujades efímeres. Els contenidors temporals (vista prèvia d'imatges, esborranys de pujades) s'haurien d'autoeliminar després de 24-72 hores via una funció programada. La retenció indefinida és una responsabilitat sota les obligacions de minimització de dades del RGPD / CCPA.
  4. Executa un escaneig de FixVibe mensualment. La comprovació baas.supabase-storage-public sondeja contenidors que responen a GET + LIST anònims. S'afegeixen contenidors nous; els antics canvien de visibilitat — només l'escaneig continu detecta la deriva.

Següents passos

Executa un escaneig de FixVibe contra el teu URL de producció — els llistats d'emmagatzematge anònims apareixen sota baas.supabase-storage-public. Combina aquesta llista amb Escàner de RLS de Supabase per a la capa de taules i Clau de rol de servei de Supabase exposada a JavaScript per a l'adjacència d'exposició de claus. Per a configuracions errònies d'emmagatzematge en altres proveïdors BaaS, consulta Escàner de configuracions errònies de BaaS.

// escaneja la teva superfície de baas

Troba la taula oberta abans que ho faci una altra persona.

Introdueix un URL de producció. FixVibe enumera els proveïdors de BaaS amb què parla la teva aplicació, identifica els seus endpoints públics i informa del que un client no autenticat pot llegir o escriure. Gratis, sense instal·lació, sense targeta.

  • Pla gratuït — 3 escaneigs al mes, sense targeta al registre.
  • Identificació passiva de BaaS — no cal verificació de domini.
  • Supabase, Firebase, Clerk, Auth0, Appwrite i més.
  • Prompts de correcció amb IA a cada troballa — enganxa'ls a Cursor / Claude Code.
Llista de comprovació de seguretat de contenidors de Supabase Storage: 22 punts — Docs · FixVibe