Depurar como un pro y asegurar tu app
Objetivos de este capítulo
- Proteger tus secretos y reaccionar correctamente a una fuga
- Validar las entradas de usuario y poner límites en todas partes
- Diagnosticar metódicamente un bug en producción
La noche en que todo estuvo a punto de descarrilar
Un martes por la noche, dos mensajes caen uno tras otro. El primero viene de Karim, un alumno de humor dudoso: «Profe, puse una cosa rara en el nombre de un hábito y ahora la página muestra cualquier cosa 😂». El segundo viene de la colega de lengua: «La app iba muy lenta ayer hacia las 19 h, ¿es normal?». Tom se da cuenta de algo que todo creador de apps descubre un día: con usuarios reales llegan los bugs reales… y las travesuras reales. Su app ya no es un proyecto personal, es un servicio público en miniatura — y un servicio se asegura.
Tranquilo: la seguridad «nivel principiante pro» se sostiene en tres frentes, y ya tienes bases en cada uno. Los secretos (tus claves y contraseñas de infraestructura), las entradas (todo lo que los usuarios teclean), y los límites (lo que se tiene derecho a hacer, cuántas veces). Este capítulo recorre los tres, y luego te arma para la depuración en condiciones reales — esa en la que el bug está en casa de un usuario, en un dispositivo que no tienes, a una hora en la que no estabas.
Frente 1 — Los secretos
Ya sabes que las claves viven en un archivo .env en el lado servidor. Queda verificar dos cosas. Primero, que ese archivo está bien ignorado por Git: si se commitea, se va a GitHub con el resto — y un repositorio, aunque hoy sea privado, puede volverse público mañana. Después, que sabes reaccionar a una fuga: nunca se «esconde» una clave comprometida, se revoca (se desactiva en el panel del servicio) y se genera una nueva. Siempre, sin excepción, incluso en caso de duda.
# .gitignore — en la raíz del proyecto .env .env.local # Verificar que .env NO está siendo seguido por Git: git status # .env no debe aparecer en ninguna parte de la salida. # Si una clave se ha filtrado: no se esconde, se REVOCA # en el panel del servicio, y se genera una nueva.
Frente 2 — No confiar nunca en las entradas
Volvamos a la broma de Karim. ¿Qué hizo? Tecleó código HTML en el campo «nombre del hábito» — algo como <h1>HOLA</h1> — y la app lo mostró tal cual, interpretándolo como maquetación. Divertido aquí; grave en general: si una app muestra sin precaución lo que los usuarios escriben, un usuario malintencionado puede colar código que se ejecutará en casa de los demás. Es la familia de ataques más común de la web (los iniciados dicen «XSS»), y la defensa se llama el escapado: el texto introducido se muestra siempre como texto, nunca se interpreta como código.
El principio a grabar: toda entrada de usuario es sospechosa por defecto. Un nombre de hábito debe tratarse como texto plano, verificarse en longitud, y validarse en el lado servidor — no solo en el navegador, porque un usuario con herramientas puede saltarse todo lo que pasa en el lado cliente. No tienes que implementarlo tú mismo: debes exigirlo y probarlo. La prueba es simple y sabrosa: haz como Karim, intenta romper tu propia app.
La auditoría de seguridad: tu aliada IA
Buena noticia: la IA es notablemente buena auditando el código que ella misma ha escrito, a condición de darle un mandato preciso. Aquí tienes el prompt de auditoría de Tom — guárdalo con cariño, volverá a servir en cada etapa importante de todos tus proyectos:
Haz una auditoría de seguridad completa de mi app de seguimiento de hábitos, adaptada a mi nivel principiante. Contexto: HTML/JS en Vercel, Supabase con autenticación por enlace mágico y reglas RLS, funciones servidor para los emails y la IA, pago vía Stripe Payment Links. Verifica en prioridad: 1. claves o secretos presentes en el código del lado navegador, en el repositorio Git o en su historial 2. las entradas de usuario mostradas sin escapado: nombres de hábitos, contenidos de formularios 3. las reglas RLS: ¿puede un usuario leer o modificar los datos de otro? 4. las funciones servidor: ¿pueden llamarse sin estar conectado? ¿sin límite de frecuencia? 5. las dependencias o bibliotecas con fallos conocidos Para cada problema encontrado: explica el riesgo en una frase simple, muestra la corrección mínima, y clasifica todo por gravedad de crítico a menor. No corrijas NADA sin mi acuerdo explícito, punto por punto.
Dos exigencias dan el valor a este prompt. La clasificación por gravedad: tratas primero lo crítico, y decides con conocimiento de causa para el resto — no todos los fallos valen lo mismo, y un principiante que quiere corregirlo todo de golpe no corrige nada bien. Y el «no corrijas nada sin mi acuerdo»: una auditoría que modifica el código a la vez que lo analiza es incontrolable. Primero comprender, después corregir, una corrección a la vez — el método del capítulo 4 también se aplica a la seguridad.
Frente 3 — Poner límites en todas partes
Tercer frente, el más simple de entender: todo lo que no tiene un límite explícito acabará siendo llevado al absurdo — por malicia, por accidente, o por un robot. En el capítulo 8, limitaste los emails y las llamadas de IA; generaliza ahora el reflejo a toda la app. Cada campo tiene una longitud máxima, cada lista tiene un tamaño máximo, cada acción tiene una frecuencia máxima. Y cada rechazo se acompaña de un mensaje educado y claro — el límite protege, no castiga.
- Nombre de hábito: 50 caracteres máximo, solo texto plano.
- Número de hábitos por cuenta: 30 máximo — nadie sigue 200, pero un script puede crear 100 000.
- Resumen por email: 1 envío por usuario y por día.
- Mensaje de IA: 1 llamada por usuario y por día, techo de gasto mensual en el proveedor.
- Creación de cuenta: protegida por la verificación de email del enlace mágico — ya en marcha, gracias capítulo 6.
flowchart TD
E["Entrada o acción de usuario"] --> V{"¿Contenido válido?"}
V -->|"No"| R["Mensaje de error claro y educado"]
V -->|"Sí"| L{"¿Dentro de los límites?"}
L -->|"No"| R2["Rechazo explicado: límite alcanzado"]
L -->|"Sí"| S["Tratamiento y almacenamiento seguros"]Depurar en producción: el método
Queda el mensaje de la colega: «iba lento ayer hacia las 19 h». Bug típico de producción: no lo viste, no puedes reproducirlo a voluntad, y el usuario casi no da detalles. El método pro se sostiene en tres movimientos: recopilar (hacer al usuario las preguntas correctas: qué dispositivo, qué navegador, qué hora, qué acción precisa, una captura de pantalla), consultar (los registros — «logs» — de Vercel y Supabase, que graban lo que realmente pasó en el servidor a esa hora), y conjeturar (formular hipótesis clasificadas, y probarlas una a una, de la más simple a la más compleja).
Bug en producción a diagnosticar metódicamente. Contexto: un alumno me dice que la app «borra sus marcas» en su teléfono Android con Chrome, ayer hacia las 19 h. En mi ordenador, imposible reproducirlo. De lo que dispongo: los logs de Vercel de esa tarde, el acceso al panel de Supabase, y la posibilidad de escribir de nuevo al alumno. Guíame en tres tiempos: 1. la lista exacta de preguntas que hacer al alumno para acotar el contexto 2. qué buscar exactamente en los logs de Vercel y en los datos de Supabase en torno a las 19 h 3. cómo simular un móvil Android y una red lenta desde mi navegador para intentar reproducirlo Propón después tus 3 hipótesis más probables, clasificadas de la más simple de verificar a la más compleja, con la prueba a hacer para cada una.
Fíjate en la estructura: este prompt no pide una solución, pide una investigación. Es el reflejo correcto ante un bug no reproducido — buscar la corrección antes de haber acotado la causa es corregir al azar. Las «3 hipótesis clasificadas» te evitan la otra trampa: explorar la pista exótica antes que la pista banal. En la vida real, la hipótesis banal gana nueve de cada diez veces: una red que se corta en el mal momento, una versión vieja en caché, una sesión caducada.
La copia de seguridad, tu seguro de vida
Última pieza del dispositivo: la copia de seguridad de los datos. Tu código está a salvo en Git, pero los hábitos y las marcas de tus usuarios solo viven en la base. Una mala maniobra en el panel — una tabla vaciada con un clic demasiado rápido — y todo desaparece. Verifica lo que tu plan de Supabase guarda automáticamente, y complétalo con una exportación regular (la IA puede crearte un pequeño script de exportación, o usa la función de exportación del panel). Y sobre todo, haz una vez el ejercicio de restauración: una copia de seguridad nunca probada es una promesa, no una protección.
Con sus tres frentes cubiertos, su diario de incidentes empezado y su primera copia de seguridad probada, Tom duerme mejor. Karim recibió un mensaje educado («nombre de hábito no válido 😉»), la lentitud de las 19 h resultó ser una red de internado saturada — hipótesis banal, como estaba previsto. La app es sólida. Es hora de mirarla de otra manera: ya no como un proyecto, sino como un producto. Ese es el capítulo final.
Contexto
Tom dedica una velada completa a la revisión de seguridad: auditoría por la IA, correcciones por gravedad, límites en todas partes, y primera prueba de restauración de copia de seguridad. De propina, se permite el placer de jugar a ser Karim: intentar romper su propia app antes de que otro se encargue. Despliega el mismo programa en tu app — es la velada más rentable de tu recorrido.
Instrucciones
- Verifica tus secretos: .env en el .gitignore, git status limpio, y busca «key» en las fuentes del lado navegador (F12).
- Juega a ser el atacante: teclea HTML en tus campos, textos de 5000 caracteres, haz clic frenéticamente — anota todo lo que se rompa.
- Lanza el prompt de auditoría de seguridad completa y lee el informe entero antes de corregir nada.
- Corrige los problemas por gravedad decreciente, UNA corrección a la vez, con prueba y commit tras cada una.
- Pon tus límites (longitudes, cantidades, frecuencias) con mensajes de rechazo educados, y prueba cada límite.
- Exporta una copia de seguridad de tu base, haz el ejercicio de restauración en un proyecto de prueba — y anota el procedimiento en tu diario.
En resumen
- Tres frentes: los secretos, las entradas de usuario, los límites — cubre los tres y eliminas lo esencial del riesgo.
- Una clave que ha tocado Git está comprometida para siempre: se revoca y se regenera, nunca se «esconde».
- Toda entrada de usuario es sospechosa: escapada al mostrarse, validada en el lado servidor, limitada en longitud.
- La auditoría con IA funciona con un mandato preciso: perímetro, clasificación por gravedad, y ninguna corrección sin tu acuerdo.
- Cada campo, lista y acción recibe un límite explícito, con un mensaje de rechazo educado.
- Bug en producción: recopilar el contexto, consultar los logs, conjeturar hipótesis clasificadas de lo banal a lo exótico.
- Una copia de seguridad nunca restaurada es una promesa, no una protección: prueba la restauración una vez.
Quiz — comprueba tu comprensión
1. Descubres que una clave API se subió a GitHub hace una semana. ¿Qué haces?
2. Karim teclea HTML en un campo y la página lo interpreta. ¿Cómo se llama la defensa?
3. ¿Por qué validar las entradas en el lado servidor y no solo en el navegador?
4. ¿Cuáles son las dos exigencias clave del prompt de auditoría de seguridad?
5. Un usuario señala un bug que no puedes reproducir. ¿Por dónde empiezas?