Seguridad de aplicaciones: OWASP Top 10:2025
Inicia sesión para guardar tu progreso en todos tus dispositivos. Mientras tanto, se guarda en este navegador.
Por qué importa
La seguridad es donde el código generado por IA falla con más frecuencia y donde sale más caro. Los datos de Veracode de 2026 sitúan la tasa de aprobación en seguridad del código de IA en torno al 56%. Este módulo dura dos semanas y es el filtro más exigente del programa.
Resultados de aprendizaje
- Aplicar el OWASP Top 10:2025 a tu propia aplicación.
- Implementar correctamente la autenticación y la autorización (OAuth/OIDC, sesiones, rotación de JWT, IAM, RLS).
- Gestionar los secretos para que ninguno llegue nunca al código, a los bundles del frontend ni a los logs.
- Prevenir inyecciones (SQL, XSS, SSRF) y ataques desde el navegador (CSRF, CORS mal configurado).
- Defender el perímetro con rate limiting, WAF y protección DDoS.
- Ejecutar SAST, DAST y escaneo de secretos y dependencias en CI.
El OWASP Top 10:2025
| ID | Riesgo | Fallo típico del código de IA |
|---|---|---|
| A01 | Broken Access Control (control de acceso roto) | El endpoint comprueba el login pero no la propiedad; RLS desactivado; IDOR con IDs secuenciales |
| A02 | Security Misconfiguration (configuración insegura) | Debug activado, credenciales por defecto, CORS permisivo *, errores demasiado detallados, buckets de almacenamiento abiertos |
| A03 | Software Supply Chain Failures (fallos en la cadena de suministro) | Paquetes alucinados o sin versión fijada, dependencias comprometidas, builds sin firmar |
| A04 | Cryptographic Failures (fallos criptográficos) | Criptografía casera, contraseñas con MD5/SHA1, secretos en texto plano |
| A05 | Injection (inyección) | SQL concatenado con strings, dangerouslySetInnerHTML, comandos de shell con entrada del usuario |
| A06 | Insecure Design (diseño inseguro) | Sin modelo de amenazas; abuso de la lógica de negocio (cantidades negativas, cupones acumulados) |
| A07 | Authentication Failures (fallos de autenticación) | Sin límite de intentos en el login, flujos de recuperación débiles, tokens de larga duración, sin MFA |
| A08 | Software or Data Integrity Failures (fallos de integridad) | Webhooks sin verificar, actualizaciones sin firmar, deserialización insegura |
| A09 | Security Logging and Alerting Failures (fallos de registro y alertas) | Sin log de auditoría; sin alerta ante fuerza bruta; secretos en los logs |
| A10 | Mishandling of Exceptional Conditions (mal manejo de condiciones excepcionales) | Fail-open ante errores, excepciones silenciadas, stack traces visibles para el usuario |
Novedades de 2025: Supply Chain pasó a ser una categoría propia en A03, y Mishandling of Exceptional Conditions entró en A10. Las dos son justo donde las herramientas de IA son más débiles.
Lecciones
5.1 Control de acceso (A01, 68)
- Autenticación = quién eres. Autorización = qué puedes hacer. El código de IA suele resolver lo primero y olvidar lo segundo.
- Comprueba la autorización en cada petición, en el servidor, para cada objeto (
WHERE id = $1 AND org_id = $currentOrg). - Denegar por defecto. Roles y permisos en un solo lugar (módulo de políticas o RLS), no en
ifdispersos. - IAM para la infraestructura: cada servicio tiene su propia identidad con el mínimo privilegio; nada de claves de administrador compartidas; cuentas separadas para dev, staging y prod.
- Nunca expongas al cliente claves de service role o de administrador. En Supabase, la anon key es pública por diseño, así que RLS es tu único muro.
5.2 Autenticación, OAuth y tokens (69, 70)
- No construyas la autenticación desde cero. Usa un proveedor probado (Supabase Auth, Clerk, Auth0, WorkOS para SSO empresarial).
- OAuth 2.0 / OIDC: flujo Authorization Code con PKCE para navegadores y móviles. Valida
state,nonce, el emisor (issuer) y la audiencia. - Sesiones: cookies
HttpOnly,Secure,SameSite=LaxoStrict. No guardes tokens en localStorage. - Rotación de JWT: access tokens de vida corta (5 a 15 minutos), refresh tokens rotativos con detección de reutilización, claves de firma rotadas mediante JWKS con identificadores de clave (
kid), nuncaalg: none, y verifica siempre firma, expiración y audiencia. - Los compradores empresariales esperan: MFA, SSO (SAML/OIDC), aprovisionamiento SCIM y revocación de sesiones.
5.3 Gestión de secretos (67)
- Los secretos viven en un gestor de secretos o en las variables de entorno de la plataforma, nunca en git, nunca en variables
NEXT_PUBLIC_*/VITE_*(esas se envían al navegador). - Hook de pre-commit + escaneo en CI (gitleaks, GitHub secret scanning con push protection).
- Un secreto filtrado se rota, no basta con borrarlo: el historial de git y los forks lo conservan para siempre.
- Claves separadas por entorno; API keys con el mínimo alcance (claves restringidas de Stripe, tokens con scope limitado).
- Límites de gasto en cada API key de pago (LLM, SMS, mapas). Si no, una clave filtrada es un cheque en blanco.
5.4 Criptografía y cifrado (72, A04)
- Contraseñas: argon2id o bcrypt a través de tu proveedor de autenticación. Nunca hagas tú el hash con SHA.
- Cifrado en reposo: cifrado gestionado de la base de datos y del almacenamiento activado, copias de seguridad cifradas. Cifrado a nivel de campo para datos muy sensibles (números de documento de identidad, datos bancarios), con las claves en un KMS.
- Usa librerías (libsodium, el KMS de la plataforma); nunca inventes criptografía.
5.5 Inyección (78, 79, 80)
- Inyección SQL: consultas parametrizadas o un query builder/ORM. Nunca interpoles strings en SQL, tampoco en las vías de escape "raw".
- XSS: los frameworks escapan por defecto; las zonas de peligro son
dangerouslySetInnerHTML,v-htmly renderizar markdown o salida de un LLM como HTML. Sanea con DOMPurify; define una Content-Security-Policy. - SSRF: cualquier funcionalidad que descargue una URL proporcionada por el usuario (vistas previas de enlaces, webhooks, "importar desde URL", agentes de IA que navegan) puede apuntarse a
169.254.169.254(metadatos de la nube) o a servicios internos. Usa allowlists de dominios, resuelve y bloquea los rangos de IP privados, desactiva las redirecciones o vuelve a comprobar tras cada una, y ejecuta los fetchers en una red aislada.
5.6 Seguridad en el navegador (76, 77)
- CORS no es una barrera de seguridad para tu servidor; controla qué orígenes pueden leer las respuestas desde el navegador. Nunca reflejes un
Originarbitrario conAccess-Control-Allow-Credentials: true. Usa una allowlist de orígenes exactos. - CSRF: cookies
SameSitemás tokens CSRF o comprobación de origen en las peticiones que cambian estado cuando usas autenticación por cookies. - Cabeceras de seguridad: CSP, HSTS,
X-Content-Type-Options: nosniff,Referrer-Policy,frame-ancestors.
5.7 Perímetro: rate limiting, WAF, DDoS (1, 74, 75)
- Aplica rate limiting por IP, por usuario y por API key, con límites más estrictos en login, registro, recuperación de contraseña, OTP y cualquier endpoint que cueste dinero (LLM, SMS, email).
- Algoritmos: token bucket o ventana deslizante, almacenados en Redis o en el edge. Devuelve
429conRetry-After. - WAF (Cloudflare, AWS WAF) con reglas OWASP gestionadas; protección contra bots en el registro.
- La protección DDoS viene en gran parte de tu CDN; asegúrate de que el origen no sea accesible directamente ni se pueda saltar.
5.8 Condiciones excepcionales (A10)
- Fail closed (fallar en cerrado): si la comprobación de autenticación lanza un error, deniega. Si la comprobación antifraude agota el tiempo, retén la transacción, no la apruebes.
- Nunca muestres stack traces a los usuarios; regístralos con un ID de petición.
- Captura errores específicos; no silencies todas las excepciones.
5.9 Modelado de amenazas (A06)
STRIDE en 30 minutos por funcionalidad: Spoofing (suplantación), Tampering (manipulación), Repudiation (repudio), Information disclosure (revelación de información), Denial of service (denegación de servicio), Elevation of privilege (escalada de privilegios). Dibuja las fronteras de confianza; enumera casos de abuso ("¿y si la cantidad es -1?").
5.10 Seguridad en el pipeline
| Tipo de herramienta | Ejemplo | Detecta |
|---|---|---|
| Escaneo de secretos | gitleaks, GitHub push protection | Claves en el código |
| SAST | Semgrep, CodeQL | Inyección, patrones inseguros |
| SCA | Dependabot, Snyk, OSV-Scanner | Dependencias vulnerables |
| DAST | OWASP ZAP | Configuración incorrecta en ejecución, cabeceras, XSS |
| Contenedores/IaC | Trivy, Checkov | Imágenes y configuración de infraestructura defectuosas |
Lab 5 (dos semanas): Ataca tu propia app
Semana A, romper: usa una segunda cuenta y un proxy de navegador (ZAP o Burp Community).
- Intenta leer o editar los registros de otro usuario cambiando los IDs (IDOR).
- Llama directamente a la base de datos con la anon key pública.
- Inyecta
<script>en cada campo de texto y en la salida de markdown o del LLM. - Apunta cualquier funcionalidad que descargue URLs a
http://169.254.169.254/y ahttp://localhost. - Haz fuerza bruta sobre el login y la recuperación de contraseña; satura el endpoint más caro.
- Busca secretos en el bundle JS de producción.
Semana B, corregir y demostrar: corrige cada hallazgo, añade un test de regresión por hallazgo y conecta los escáneres a CI.
Definition of Done
Paquete de prompts de IA
- "Actúa como pentester. Para cada ruta de esta app, enumera cómo un usuario autenticado podría acceder a los datos de otro usuario. Después escribe tests para cada caso."
- "Encuentra todos los lugares donde se leen secretos o variables de entorno. Marca cualquiera que pueda llegar al bundle del cliente."
- "Encuentra todos los lugares donde descargamos una URL derivada de la entrada del usuario. Añade protección SSRF que bloquee los rangos privados, de loopback y link-local después de la resolución DNS."
- "Encuentra todos los bloques catch. Marca cualquiera que falle en abierto o silencie errores."