Módulo 4 · Autenticación y seguridad

Lección 22 — OWASP Top 10

Inyección SQL, XSS, CSRF, SSRF y control de acceso roto — con ejemplos reales.

Publicada
En esta lección
  1. Ejercicio 1 — SQLi: el f-string que arde
  2. Ejercicio 2 — XSS: del JSON al DOM
  3. Ejercicio 3 — SSRF: el guard
  4. Ejercicio 4 — check --deploy y el browseable API
  5. Ejercicio 5 — Componentes y dependencias
  6. Ejercicio 11 — Los tres del §11, cazados
  7. Ejercicio 12 — security.txt y el runbook
  8. Entrega

Entorno local, ataques contra TU app. No mires solutions.md hasta entregar.

Ejercicio 1 — SQLi: el f-string que arde

  1. Escribe (solo en un branch de prueba, para aprender) una vista que filtre eventos con cursor + f-string: f"... WHERE title LIKE '%{q}%'". Ejecuta con q = "x' OR '1'='1". ¿Qué devolvió? Y con q = "x'; DROP TABLE events_reservation; --" (en una BD de prueba desechable).
  2. Reescríbelo con parámetros %s: repite los payloads. ¿Qué sale ahora?
  3. Tu available_seats usa el ORM: demuestra con un input tipo payload ("'; DROP -- como row de asiento) que nada explota — el ORM parametrizó.

Ejercicio 2 — XSS: del JSON al DOM

  1. Crea un evento cuyo título sea <img src=x onerror=alert('xss')>. Consúmelo desde una mini-página HTML con fetch + innerHTML: ¿se ejecuta? (es el riesgo del FRONTEND, no de tu API).
  2. Cambia a textContent (o el escape del framework): ¿se ejecuta? Registra la regla para tu equipo frontend: "el HTML de usuario jamás va por innerHTML; si hay HTML rico legítimo: sanitizar con DOMPurify server-side o al render".
  3. Cabeceras CSP básicas en tu response (o Nginx): Content-Security-Policy: default-src 'self' — ¿qué bloquea esto del escenario anterior como segunda capa?

Ejercicio 3 — SSRF: el guard

  1. Añade (branch de prueba) un endpoint POST /api/tools/fetch/ {"url":...} que devuelve el título de la URL. Atácalo: http://localhost:6379/ y http://169.254.169.254/latest/meta-data/ (local no tiene metadata real, pero la técnica es la del ataque a nube).
  2. Implementa el guard: esquema http/https only, resolve con socket.getaddrinfo y rechaza IPs privadas/loopback/link-local (bloquear el rango 169.254.0.0/16, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16), y whitelist de dominios si el caso lo permite.
  3. ¿Por qué la resolución DNS debe hacerse ANTES del fetch y contra la IP a la que conectarás (DNS rebinding)?

Ejercicio 4 — check --deploy y el browseable API

  1. Corre python manage.py check --deploy: lista los warnings que te da hoy.
  2. Configura el bloque de settings seguro de la lección (HSTS, cookies seguras, nosniff, referrer, X-Frame-Options DENY) y vuelve a correr: ¿queda verde?
  3. Apaga el browseable API en producción (DEFAULT_RENDERER_CLASSES solo JSON) y justifica qué exponía.

Ejercicio 5 — Componentes y dependencias

  1. pip install pip-audit y corre pip-audit sobre tu requirements: ¿cuántas vulnerabilidades conocidas hay en tus versiones? Anota las 2 más graves.
  2. Fija versiones exactas (==) en requirements y añade pip-audit a tu "pipeline local" (script). ¿Por qué el pinning + audit es la pareja mínima de A06?

Ejercicio 11 — Los tres del §11, cazados

  1. Mass assignment: crea el endpoint vulnerable a propósito (fields = "__all__" en el serializer de perfil) y demuéstralo: PATCH del perfil con "is_staff": true → ¿el usuario se auto-escaló? Fix: serializer explícito + test de regresión que envía el campo y verifica que no llegó.
  2. Timing: compara secret == adivinanza vs hmac.compare_digest con 1000 mediciones (el timeit del 37): ¿la diferencia de tiempo revela caracteres correctos en la primera? Pega los números.
  3. Dependencias: introduce un typo en una dependencia de test (pip install requets en un venv de laboratorio): ¿qué instala? Después: pinnea tus dependencias con hashes (pip-compile --generate-hashes) y corre pip-audit — el reporte del 41.

Ejercicio 12 — security.txt y el runbook

  1. Escribe tu /.well-known/security.txt (contacto, expiración, política de divulgación, encriptación para reportes) y el test que verifica que existe y expira a futuro.
  2. El runbook del hallazgo (§12) aplicado a una vulnerabilidad simulada ("reporte externo: el endpoint de eventos filtra emails en el listado de reservas"): los 5 pasos con comandos reales (¿cómo contienes? ¿qué test de regresión? ¿notificas?). Máx 1 página (48).
  3. La pregunta raíz del postmortem: ¿qué PIEZA del curso (review del 50, pipeline del 41, tests del 34) habría cazado ese filtrado? Si la respuesta es "ninguna": esa es la acción P1.

Entrega

Pega outputs de los ataques (¡en tu entorno!) y los guards implementados. Después: Lección 23 — Secretos, rate limiting y RGPD.