TIPS 24 · PORTA

¿Tu base de datos responde a todo el mundo?

La prueba de dos minutos para saber si la base de datos de tu app responde también a quien no ha iniciado sesión, y el prompt que la cierra. Solo en tu app.

Qué es y por qué importa

Muchas apps hechas con Claude Code usan un backend ya listo, como Supabase o Firebase. Es cómodo: la app habla directamente con la base de datos, desde el navegador o el móvil, sin un servidor tuyo en medio.

Para eso, la app lleva consigo dos cosas: la dirección del proyecto y una clave pública. Cualquiera que abra tu app puede verlas, basta con mirar las peticiones en el navegador. Y es normal: esa clave está hecha para estar ahí. No es una contraseña, solo dice «esta petición viene de mi app».

La cuestión es qué hay detrás de la puerta. Quien decide quién puede leer qué no es la clave: son las reglas de la base de datos. En Supabase se llaman Row Level Security (seguridad a nivel de fila), en Firebase reglas de seguridad. En palabras sencillas: para cada tabla escribes quién puede leer, añadir, modificar y borrar qué filas. Por ejemplo: «cada usuario ve solo sus pedidos».

Si esas reglas faltan, o están escritas demasiado abiertas, la clave pública lo abre todo. Quien copia la dirección y la clave del navegador puede leer las tablas: correos, nombres, mensajes, todo lo que has metido ahí. A veces incluso modificarlas. No hace falta ser un hacker: basta una línea en el terminal.

Claude crea las tablas y la app funciona, porque a ti, con la sesión iniciada, los datos te llegan. Que también le lleguen a quien no tiene ninguna cuenta, usando la app no lo ves. Solo lo ves si lo pruebas.

Antes de nada: solo en tu app

Esta prueba la haces en tu proyecto, con tus datos o con usuarios de prueba. Nunca en apps o bases de datos de otros, ni siquiera «solo para ver»: entrar en un sistema sin permiso puede ser un delito, en Italia como en muchos otros países. Si crees que la app de otra persona está abierta, no la pruebes: escribe a quien la gestiona.

1. La prueba, en dos minutos

Tres partes: la primera encuentra la clave, la segunda mira qué ve quien no ha iniciado sesión, la tercera si un usuario lee los datos de otro. Las describo en Supabase; para Firebase, mira más abajo.

a. Encuentra la clave

  1. Abre tu app en el navegador, sin iniciar sesión.
  2. Clic derecho > Inspeccionar > pestaña Red (Network), y luego recarga la página.
  3. Busca las peticiones a la base de datos. En Supabase son direcciones que terminan en .supabase.co.
  4. Haz clic en una petición: ahí ves la dirección del proyecto y la clave pública (publishable o anon).

Si no encuentras peticiones a la base de datos, ve a una página que cargue datos y vuelve a mirar.

b. Intenta leer sin iniciar sesión

Sin iniciar sesión, abre un terminal y lanza esta línea. Pon tu proyecto, tu clave pública y el nombre de una de tus tablas:

La línea
curl "https://TU-PROYECTO.supabase.co/rest/v1/NOMBRE_TABLA?select=*" -H "apikey: CLAVE_PUBLICA"

Si vuelven filas de usuarios, la puerta está abierta. Si vuelve una lista vacía, [], o un error de permisos, esa tabla no responde a cualquiera que pase. Dos cuidados: comprueba que en la tabla haya datos de verdad, si no una lista vacía no te dice nada. Y repítelo para cada tabla, no solo para una.

c. Prueba como usuario A

Crea dos usuarios de prueba, A y B, y haz que cada uno guarde algo: un perfil, una nota, un pedido. Luego entra como A y copia su token de acceso: lo encuentras en la pestaña Red, en la cabecera Authorization de las peticiones hechas después del inicio de sesión. Después lanza:

La línea
curl "https://TU-PROYECTO.supabase.co/rest/v1/NOMBRE_TABLA?select=*" -H "apikey: CLAVE_PUBLICA" -H "Authorization: Bearer TOKEN_DE_A"

Las dos cabeceras tienen funciones distintas. La clave pública va siempre en apikey. Authorization: Bearer lleva solo el token de acceso de un usuario que ha iniciado sesión, nunca la clave pública y nunca la secreta. Por eso la primera línea solo tiene apikey: ahí no hay ningún usuario.

Si entre las filas están las de B, A lee a B. Es el agujero más fácil de pasar por alto: la puerta está cerrada a quien no ha iniciado sesión, pero una vez dentro cada uno lo ve todo. Trata el token de A como una contraseña: con él eres A. Úsalo solo para la prueba y no lo pegues en ningún sitio.

Si no quieres hacerlo a mano

Pídeselo a Claude, dentro de tu proyecto. Él hace las peticiones por ti:

El prompt
Haz tú la prueba: con la clave pública y sin iniciar sesión intenta leer cada tabla; luego, con dos usuarios de prueba, comprueba si A ve los datos de B. Dime tabla por tabla qué está abierto. No modifiques nada.

Si Claude Code te pide permiso para lanzar un comando, lee lo que va a hacer antes de decir que sí. «No modifiques nada» sirve justo para esto: la prueba lee, no escribe.

2. El prompt que lo arregla

Cuando sabes qué está abierto, ciérralo. Este es el prompt que uso yo:

El prompt
Cada usuario ve solo sus filas. Activa la Row Level Security en cada tabla y escribe las reglas: lectura, inserción, modificación y borrado solo en las filas del usuario con sesión iniciada. Las tablas realmente públicas (p. ej. un catálogo), solo de lectura. Revisa también las vistas, las funciones RPC y los buckets de Storage. Hazme una lista de todo con la regla que has puesto, luego repite la prueba y muéstrame que A ya no ve a B.

Las palabras están elegidas. «Lectura, inserción, modificación y borrado» porque en Supabase las reglas se escriben para cada operación: si cierras solo la lectura, alguien todavía puede escribir o borrar. «Las vistas, las funciones RPC y los buckets de Storage» porque los datos no salen solo de las tablas. En Supabase una vista, por defecto, se salta las reglas de las tablas que lee; una función puede estar escrita de forma que se las salte; los archivos subidos tienen reglas propias. Y «repite la prueba» porque una regla se comprueba probándola, no leyéndola.

3. Dos cosas que debes saber

Mejor una puerta cerrada

En Supabase, con la Row Level Security activa y ninguna regla escrita, con la clave pública no pasa nada: mejor una puerta cerrada que una abierta. Luego abres solo lo que hace falta. Si después del arreglo una pantalla deja de cargar datos, no apagues la seguridad: falta una regla. Pídele a Claude que añada esa, y nada más.

Las dos claves

  • La clave pública (publishable, o anon en los proyectos más antiguos) puede estar en la app y en el navegador. Por sí sola abre solo lo que las reglas permiten.
  • La clave secreta (secret o service_role) se salta todas las reglas: solo en el servidor, nunca en la app, nunca en GitHub.

Si la clave secreta ha acabado en la app o en un repositorio, dala por quemada. Crea una nueva en el panel de Supabase, ponla en lugar de la antigua allí donde haga falta, y solo después elimina o desactiva la antigua. Quitarla del código no basta: se queda en el historial y en quien ya la ha visto.

El prompt
Busca en el código de la app, y en todo lo que acaba en el navegador o en la app publicada, si está la clave secreta de Supabase (secret o service_role). Revisa también el historial de git. Dime dónde la encuentras. No modifiques nada.

Si usas Firebase

La misma idea, allí se llaman reglas de seguridad. También en Firebase la clave de la app no es un secreto: sirve para identificar el proyecto. Lo que protege los datos son las reglas.

La regla que hay que buscar es la que deja pasar a todo el mundo, tipo allow read, write: if true. La documentación de Firebase dice que no se use nunca en producción. En su lugar hacen falta reglas que comprueben quién ha iniciado sesión y de quién es el documento.

El prompt
Lee las reglas de seguridad de Firebase de mi proyecto. Dime qué colecciones puede leer o escribir quien no ha iniciado sesión, y si un usuario puede leer los documentos de otro. Luego proponme reglas en las que cada usuario vea y modifique solo sus datos. No publiques nada hasta que te lo diga.

Errores comunes

  • Hacer la prueba en una sola tabla. Cada tabla tiene sus reglas: pruébalas todas.
  • Cerrar solo la lectura. Escribe las reglas también para inserción, modificación y borrado.
  • Cerrar las tablas y olvidarse de vistas, funciones y archivos. Revísalos también, con la misma prueba.
  • Una regla que deja leerlo todo a cualquiera que haya iniciado sesión. El control correcto es sobre quién es el dueño de la fila, no sobre tener la sesión iniciada.
  • Apagar la seguridad cuando una pantalla deja de funcionar. Añade la regla que falta en lugar de volver a abrirlo todo.
  • Poner la clave secreta en la app o en el repositorio. Úsala solo en el servidor y, si se ha filtrado, sustitúyela.

Lista de comprobación

  • He hecho la prueba sin iniciar sesión en cada tabla.
  • Con dos usuarios de prueba, A no ve los datos de B.
  • Cada tabla tiene reglas para lectura, inserción, modificación y borrado.
  • He revisado también vistas, funciones RPC y buckets de Storage.
  • Las tablas públicas son solo de lectura.
  • La clave secreta está solo en el servidor.
  • He repetido la prueba después del arreglo.

Preguntas frecuentes

¿Puedo hacer esta prueba en la app de otra persona, por curiosidad?

No. Solo en tu app. Leer datos de un sistema sin permiso puede ser un delito, aunque la puerta esté abierta. Si sospechas un problema, avisa a quien gestiona la app.

Después del arreglo la app ya no carga algunos datos. ¿Qué he hecho mal?

Probablemente nada: la puerta ahora está cerrada y falta una regla para ese caso. Dile a Claude qué pantalla no carga y pídele la regla más estricta que baste, luego repite la prueba con A y B.

¿Tengo que repetirla de vez en cuando?

Cada vez que añadas una tabla o cambies quién puede ver qué. Las reglas valen tabla por tabla, y una tabla nueva puede nacer sin ninguna.

← Todas las guías