Stack: Django/DRF · Proyecto: TicketFlow Estado: Publicada Prerrequisito: Lección 21 — Autorización
Objetivos
- Recorrer el OWASP Top 10 (2021) con el ataque concreto y la defensa concreta en tu stack.
- Encontrar y cerrar las debilidades que tu propio proyecto ya tiene (inventario honesto).
- Aprender el triaje: qué arreglas hoy, qué vigila el framework, qué audita un pentest.
1. A01 — Broken Access Control (el #1 real)
El agujero de la 21 (IDOR, escalada de rol, reglas solo en frontend). Defensas ya implementadas: queryset filtrado, permissions de objeto, reglas en el servicio, tests de regresión de escalada. El check que falta SIEMPRE: revisar cada endpoint nuevo con la matriz de la 21 — el OWASP no se "arregla una vez", es una disciplina por-PR.
2. A02 — Cryptographic Failures
Datos sensibles sin cifrar o con cifrado débil:
- En tránsito: TLS obligatorio (HSTS de la 01), nada sensible por HTTP.
- En reposo: hashes de contraseña con argon2 (20); secretos TOTP cifrados en reposo (20); tokens de reset hasheados.
- Cifrado de campo:
django-fernet-fields/field custom con clave de settings/KMS (23) para lo que la BD no debe leer (documento de identidad del comprador si lo pidiera el negocio). - Nunca: inventar "cifrado" propio, MD5/SHA1 para nada de seguridad, contraseñas reversibles.
3. A03 — Injection (SQL, comandos, plantillas)
- SQLi: el ORM parametriza SIEMPRE. El agujero aparece con
.raw(),extra()o cursores con f-strings:cursor.execute(f"SELECT... {user_input}")= inyección servida. Regla: parámetros%ssiempre; si el SQL dinámico es inevitable (orden por columna), whitelist de identificadores (13). - Comandos:
os.system("convert " + filename)— jamás:subprocess.run([...], shell=False)con lista, o mejor: librerías en lugar de shell. - Template injection: renderizar input de usuario con
Template(...)ejecuta código. Django templates auto-escapan; el riesgo es usar el input como plantilla. - XSS (encaja aquí en DRF): tu API devuelve JSON y el frontend escapa al renderizar (React/Vue lo hacen por defecto) — el agujero aparece con
dangerouslySetInnerHTML/v-htmlcon datos de usuario (el nombre del evento con<script>: escapar o sanitizar con DOMPurify si hay HTML rico legítimo).
4. A04 — Insecure Design / A05 — Security Misconfiguration
Diseño: las invariantes en BD (00b/10) y la matriz de autorización (21) SON seguridad de diseño: el OWASP premia prevenir en el esquema antes que parchear en la vista. Misconfiguración — el checklist de Django:
DEBUG = False # el stacktrace filtra settings y rutas
ALLOWED_HOSTS = ["ticketflow.app"] # evita host header poisoning
SECURE_SSL_REDIRECT, SECURE_HSTS_SECONDS = True, 31536000
SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE = True, True
SECURE_CONTENT_TYPE_NOSNIFF, SECURE_REFERRER_POLICY = True, "same-origin"
X_FRAME_OPTIONS = "DENY" # clickjackingpython manage.py check --deploy lo audita — entra al pipeline (41). Y los errores por defecto de DRF: browseable API apagado en producción (renderer JSON solo) para no exponer formularios de prueba.
5. A07 — Identification/Auth failures + A10 SSRF
Auth: credential stuffing (rate limit 20/23), tokens eternos (18), resets flojos (20) — todo cubierto. SSRF (Server-Side Request Forgery): tu backend hace fetch a URLs dadas por usuarios (p. ej. "avatar_url" del organizador) y un atacante pide http://169.254.169.254/ (metadata de la nube = credenciales) o http://localhost:6379/ (tu Redis). Defensa: whitelist de dominios/esquemas, resolver y bloquear IPs privadas, nunca fetch ciego de URLs de usuario.
El resto (A06 componentes vulnerables: pip-audit en CI; A08 integridad de despliegue: firmas de imágenes/dependencias pinneadas; A09 logging/monitoring: la 45/46) se cubre en sus módulos — el OWASP es un mapa, no un sprint.
6. El inventario de TicketFlow (ejercicio)
Tu proyecto ya tiene: ORM parametrizado, argon2, HMAC en webhooks, rate limit, autorización en capas, constraints como invariantes. Sus agujeros típicos pendientes: check --deploy sin pasar, browseable API activo, alguna URL de avatar/imagen de usuario (SSRF latente), logs sin sanitizar de payloads. Los ejercicios los convierten en tickets.
11. Más allá del Top 10: los tres ataques que el ranking no encabeza y sí muerden
El Top 10 es un ranking de CATEGORÍAS; los ataques concretos del día a día del backend: (1) Mass assignment: el cliente envía is_staff: true en el JSON del perfil y el serializer lo asigna — la cura: serializers explícitos (solo los campos del contrato, 15) jamás fields = "__all__" (la 21 lo completa con permisos por campo); (2) Timing attacks: la comparación de secretos con == filtra por tiempo — la cura: hmac.compare_digest SIEMPRE (ya la usaste en la 17/27) y respuestas de reset con timing uniforme (la 20); (3) Dependency confusion / typosquatting: el pip install requests de un typo instala el paquete del atacante — la cura: lockfile con hashes (40), proxy privado para el nombrado interno, y el pip-audit del 41.
12. La respuesta a la vulnerabilidad: el runbook del hallazgo
Encontrar (o que te reporten) una vulnerabilidad es el inicio del proceso, no el final: (1) triage en <24 h: explotable en TU contexto (el triage de CVE del 40), severidad, quién decide; (2) contención si está siendo explotada: el flag/rollback del 41, el rate limit del 23, la revocación de secretos (27); (3) fix + test de regresión (33: el test que reproduce el exploit, ahora verde); (4) divulgación responsable: si afecta a usuarios (brecha, 56): el runbook de notificación 72 h; si no: el changelog discreto; (5) el postmortem (47) con la pregunta raíz: ¿por qué el review/pipeline no lo cazó? — y la acción que lo cazará la próxima.
El programa de recompensas (security.txt + correo de seguridad) convierte el reporte ajeno en regalo: la página /.well-known/security.txt de TicketFlow con contacto, política de divulgación y PGP — 20 líneas que el pentester honesto busca antes de reportar a un foro.
- ¿Por qué el OWASP #1 es control de acceso y no inyección? ¿Qué disciplina lo sostiene?
- Explica a un junior por qué
cursor.execute(f"... {email}")es grave yexecute("... %s", [email])no. - Tu SPA muestra
event.descriptionque el organizador escribe con HTML: ¿dónde está el riesgo de XSS y qué decisión tomas (escapar vs sanitizar)? - ¿Por qué SSRF apunta a
169.254.169.254y qué obtiene el atacante si lo logras? - ¿Qué tres checks de
check --deployfallarían en tu proyecto hoy?
Continúa con los ejercicios. Las solutions.md solo tras intentarlo.