00:00:00Este mes se publicó un informe que analizó unas 20 000 aplicaciones independientes y descubrió que una de cada nueve
00:00:04exponía credenciales de Supabase en el código del front-end.
00:00:08Y esto no es en un registro del servidor o en un repositorio privado.
00:00:11Está en el JavaScript que cada visitante descarga.
00:00:14Lo peor es que estas apps no fueron hackeadas; simplemente enviaron el secreto por error.
00:00:18Para ser claros, algunas llaves están hechas para ser públicas.
00:00:21El problema es el flujo de trabajo, porque el mismo error puede filtrar una llave que nunca debería
00:00:25estar en el navegador en primer lugar.
00:00:27Publicamos videos constantemente.
00:00:28No olvides suscribirte.
00:00:35Esta es la simple verdad que a veces confunde a la gente.
00:00:38Todos lo sabemos, pero es fácil pasarlo por alto cuando trabajas rápido.
00:00:41Al marcar una variable de entorno como pública, tu herramienta de compilación asume que debe estar en
00:00:46el navegador y la añade al paquete del cliente.
00:00:50Next.js lo hace con Next.public, Vite lo hace con Vite y SvelteKit utiliza
00:00:56public.
00:00:57Ese prefijo no es una etiqueta de seguridad; es, literalmente, la etiqueta de envío.
00:01:01Ya sabemos eso, pero aquí está el detalle con Supabase.
00:01:04Ciertas llaves deben ser públicas, como la "anon" o la de publicación; otras son privadas, como la
00:01:10de rol de servicio o las llaves secretas.
00:01:12Si una llave privada termina en el navegador, bueno, ya se imaginarán qué pasa.
00:01:17En ese caso, la seguridad a nivel de fila (RLS) no te salvará.
00:01:20La documentación de Supabase es clara: las llaves de servicio pueden saltarse la RLS.
00:01:24Así que, si esa llave está en tu front-end, todo tu trabajo de políticas deja de importar.
00:01:29Ahora les mostraré exactamente cómo ocurrió esto usando mi propio entorno de pruebas.
00:01:33Primero, creé una app CRUD sencilla con Next.js y la vinculé a mi Supabase.
00:01:38Aquí está mi archivo .env, y aquí el error.
00:01:41Puse una llave en una variable con el prefijo "public".
00:01:45Esta llave es para publicación, por lo que se espera que sea visible.
00:01:48El problema real es que esa misma ruta de Next.public puede filtrar accidentalmente una llave privada.
00:01:53Ejecuté "npm run build" para compilarla y luego inicié mi aplicación.
00:01:59Aquí estoy en Chrome.
00:02:00Voy a añadir rápidamente algo de información a nuestra base de datos.
00:02:05Bien, ahora puedo abrir el paquete de JavaScript compilado y voy a buscarla.
00:02:10Ahí está.
00:02:12La URL y la llave están ahí mismo, dentro del archivo que tus usuarios acaban de descargar
00:02:18en su navegador.
00:02:19Y fíjense en lo que NO pasó.
00:02:21Nadie vulneró el sistema.
00:02:22Yo mismo encontré esto, ¿ven?
00:02:24Nadie explotó ninguna vulnerabilidad.
00:02:25Solo estoy leyendo lo que la app ya envió a la red pública.
00:02:29Si tú puedes verlo, cualquiera puede.
00:02:32Abre las herramientas de desarrollo, busca en los archivos JS y ya está.
00:02:35Eso es todo lo que hay que hacer.
00:02:36Si tu plan es confiar en que nadie mirará, bueno, internet está lleno de personas y bots
00:02:41cuya única función es buscar este tipo de descuidos.
00:02:44Aquí está la solución que realmente funciona.
00:02:47El navegador solo debería llamar a tu API.
00:02:50Tu API se ejecuta en el lado del servidor.
00:02:52Ahí es donde viven las llaves privadas.
00:02:54Mueve la operación privada a una ruta de API o a una función de servidor.
00:02:58El cliente llama a tu endpoint, tu endpoint llama a Supabase; luego recompila y verifica
00:03:03el paquete de archivos.
00:03:04Si la llave ya no está en el paquete, lo has arreglado; pero no te detengas ahí,
00:03:09porque hay otras cosas que puedes hacer.
00:03:11Asegúrate de que la seguridad a nivel de fila esté activa en las tablas visibles al usuario y que tus políticas
00:03:16hagan exactamente lo que esperas.
00:03:18Dedica también tiempo a las pruebas.
00:03:19Creo que esto a veces se pasa por alto.
00:03:21Para evitar que el problema regrese... mucha gente lo arregla una vez y luego vuelve a fallar
00:03:26cuando tiene prisa.
00:03:28Así que añade protecciones: empieza con un escaneo de secretos en el CI para que la compilación falle
00:03:34si aparece una llave donde no debe.
00:03:36Luego, una regla de revisión para que cualquier cosa con "Next public" o "Vite" se trate como pública por defecto,
00:03:41porque de hecho lo es.
00:03:42Por último, implementa la rotación.
00:03:43Si tienes la más mínima sospecha de que las llaves se expusieron, rótalas.
00:03:47Es mejor que esperar a ver qué pasa en unos días.
00:03:50Esto es lo que puedes probar ahora mismo.
00:03:52Compila tu aplicación tal como la lanzas a producción.
00:03:55Busca en el resultado términos como "supabase jwt", "service secret" o cualquier token.
00:04:01Si encuentras algo privado, asume que está comprometido porque tú lo encontraste.
00:04:05Rótalo y cambia tu lógica al lado del servidor.
00:04:08Si solo vas a recordar una frase de este video, que sea esta:
00:04:11Si está en el paquete de archivos, es público.
00:04:13Nos vemos en el próximo video.