¿Qué hace supabase?
Principios fundamentales
1. Supabase cambia con frecuencia — verifica contra el changelog y la documentación actual antes de implementar.
No confíes en los datos de entrenamiento para las funciones de Supabase. Las firmas de funciones, la configuración de config.toml y las convenciones de la API cambian entre versiones.
Primero, obtén https://supabase.com/changelog.md (un índice resumido ligero, no una descarga pesada), busca etiquetas breaking-change relevantes para tu tarea y sigue la página enlazada si corresponde. Luego consulta el tema relevante usando los métodos de acceso a la documentación que se indican a continuación.
2. Verifica tu trabajo. Después de implementar cualquier corrección, ejecuta una consulta de prueba para confirmar que el cambio funciona. Una corrección sin verificación está incompleta.
3. Recupérate de los errores, no entres en un bucle. Si un enfoque falla después de 2 o 3 intentos, detente y reconsidera. Prueba un método diferente, consulta la documentación, inspecciona el error con más cuidado y revisa los registros relevantes cuando estén disponibles. Los problemas de Supabase no siempre se resuelven reintentando el mismo comando, y la respuesta no siempre está en los registros, pero a menudo vale la pena revisarlos antes de continuar.
4. Exponer tablas a la API de datos: Dependiendo de la configuración de la API de datos del usuario, es posible que las tablas recién creadas no se expongan automáticamente a través de la API de datos (REST). Si este es el caso, será necesario otorgar acceso explícitamente a los roles anon y authenticated.
Ten en cuenta que esto es independiente de RLS, que controla qué filas son visibles una vez que una tabla es accesible, no si la tabla es accesible en absoluto.
Cuando un usuario informa que una tabla creada con SQL es inesperadamente inaccesible, verifica su configuración de la API de datos y si se ha otorgado acceso a los roles mediante una instrucción GRANT SQL explícita. Al otorgar acceso público (anon/authenticated), habilita también RLS. Consulta Exponer una tabla a la API de datos para obtener el flujo de trabajo completo de configuración.
5. RLS en esquemas expuestos.
Habilita RLS en cada tabla de cualquier esquema expuesto, lo que incluye public de forma predeterminada. Esto es fundamental en Supabase porque las tablas en esquemas expuestos pueden ser accesibles a través de la API de datos cuando los roles anon/authenticated tienen acceso (consulta Exponer una tabla a la API de datos). Para esquemas privados, prefiere RLS como defensa en profundidad. Después de habilitar RLS, crea políticas que coincidan con el modelo de acceso real en lugar de aplicar por defecto el mismo patrón auth.uid() a todas las tablas.
6. Lista de verificación de seguridad. Al trabajar en cualquier tarea de Supabase que involucre autenticación, RLS, vistas, almacenamiento o datos de usuario, revisa esta lista. Estas son trampas de seguridad específicas de Supabase que crean vulnerabilidades silenciosamente:
-
Seguridad de autenticación y sesiones
- Nunca uses las reclamaciones de
user_metadataen decisiones de autorización basadas en JWT. En Supabase,raw_user_meta_dataes editable por el usuario y puede aparecer enauth.jwt(), por lo que no es seguro para las políticas de RLS ni para ninguna otra lógica de autorización. Almacena los datos de autorización enraw_app_meta_data/app_metadataen su lugar. - Eliminar un usuario no invalida los tokens de acceso existentes. Primero cierra sesión o revoca las sesiones, mantén la caducidad del JWT corta para aplicaciones sensibles y, para garantías estrictas, valida
session_idcontraauth.sessionsen operaciones sensibles. - Si usas
app_metadataoauth.jwt()para la autorización, recuerda que las reclamaciones JWT no siempre están actualizadas hasta que se renueva el token del usuario.
- Nunca uses las reclamaciones de
-
Exposición de claves de API y cliente
- Nunca expongas la clave
service_roleo secreta en clientes públicos. Prefiere las claves publicables para el código del frontend. Las clavesanonheredadas son solo para compatibilidad. En Next.js, cualquier variable de entornoNEXT_PUBLIC_se envía al navegador.
- Nunca expongas la clave
-
RLS, vistas y código de base de datos privilegiado
- Las vistas omiten RLS de forma predeterminada. En Postgres 15 y versiones posteriores, usa
CREATE VIEW ... WITH (security_invoker = true). En versiones anteriores de Postgres, protege tus vistas revocando el acceso a los rolesanonyauthenticated, o colocándolas en un esquema no expuesto. - UPDATE requiere una política SELECT. En Postgres RLS, un UPDATE necesita primero hacer un SELECT de la fila. Sin una política SELECT, las actualizaciones devuelven silenciosamente 0 filas — sin error, simplemente ningún cambio.
auth.role()está obsoleto — usa la cláusulaTOen su lugar. Supabase ha dejado obsoletoauth.role()a favor de especificar el rol objetivo directamente en la política conTO authenticatedoTO anon. Más allá de la obsolescencia,auth.role() = 'authenticated''falla silenciosamente cuando los inicios de sesión anónimos están habilitados, porque los usuarios anónimos tienen el rolauthenticatedde Postgres y pasan la verificación independientemente de si el usuario ha iniciado sesión realmente.-- Obsoleto (no usar) create policy "ejemplo" on nombre_tabla for select using ( auth.role() = 'authenticated' );TO authenticatedpor sí solo es autenticación sin autorización (BOLA / IDOR). UsarTO authenticatedsolo verifica el rol — no restringe qué filas puede acceder un usuario. El patrón correcto combinaTO authenticatedcon un predicado de propiedad enUSING:create policy "ejemplo" on nombre_tabla for select to authenticated using ( (select auth.uid()) = user_id );- Las políticas UPDATE requieren tanto
USINGcomoWITH CHECK. SinWITH CHECK, un usuario puede reasignar eluser_idde una fila a otro usuario:create policy "ejemplo" on nombre_tabla for update to authenticated using ( (select auth.uid()) = user_id ) with check ( (select auth.uid()) = user_id ); - Las funciones
SECURITY DEFINERomiten RLS. Una funciónSECURITY DEFINERse ejecuta con los privilegios de su creador — normalmente un rol conbypassrls(por ejemplo,postgres). Nunca agreguesSECURITY DEFINERpara resolver un error de permiso; elimina silenciosamente el control de acceso sin solucionar la causa subyacente. PrefiereSECURITY INVOKER. - Las funciones
SECURITY DEFINERenpublicson invocables por todos los roles. Postgres otorgaEXECUTEaPUBLICde forma predeterminada para cada función nueva, por lo que cualquier funciónSECURITY DEFINERenpublices un punto final de API pública invocable poranonyauthenticated(que heredan dePUBLIC) sin necesidad de concesiones adicionales. CuandoSECURITY DEFINERes realmente necesario (por ejemplo, para omitir RLS en una tabla de búsqueda interna), mantén la función en un esquema no expuesto, incluye siempre una verificación deauth.uid()en el cuerpo de la función y ejecutasupabase db advisorsdespués de realizar cambios.
- Las vistas omiten RLS de forma predeterminada. En Postgres 15 y versiones posteriores, usa
-
Control de acceso al almacenamiento
- Upsert en Storage requiere INSERT + SELECT + UPDATE. Otorgar solo INSERT permite nuevas subidas, pero el reemplazo de archivos (upsert) falla silenciosamente. Necesitas los tres.
-
Seguridad de dependencias y cadena de suministro
- Fija siempre las versiones de los paquetes y confirma los archivos de bloqueo al instalar paquetes de Supabase (
supabase-js,@supabase/ssr,supabase-py, etc.). Consulta la guía de seguridad npm para obtener la lista de verificación completa.
- Fija siempre las versiones de los paquetes y confirma los archivos de bloqueo al instalar paquetes de Supabase (
Para cualquier problema de seguridad no cubierto anteriormente, obtén el índice de seguridad del producto Supabase: https://supabase.com/docs/guides/security/product-security.md