Ejercicio 1 — Token bucket
- Con HGETALL/HSET separados, bajo concurrencia pasan MÁS de 5 (los threads leen el mismo "tokens" viejo y cada uno decide permitir): la raza clásica check-then-act (03/10/12: la misma lección en otro almacén).
- Con Lua (o django-ratelimit, que la usa), el script es atómico en Redis: exactamente 5 pasan y 15 reciben 429. El patrón: sube el chequeo+decremento al servidor de datos como operación única.
- 429 con
Retry-After(segundos o fecha) y body RFC 7807 (type: rate-limited). Los límites propuestos: login duro (fuerza bruta), checkout moderado (bots), API pública generoso pero presente.
Ejercicio 2 — Secretos
- Trufflehog/gitleaks sobre el historial: con la limpieza de la 05 debería salir limpio; si sale algo, la reparación es rotar (siguiente punto) — borrar el commit no arregla nada.
- Runbook de rotación dual: (1) generar nueva clave en el proveedor; (2) configurar
GATEWAY_SECRETS=[nueva, vieja](verificación acepta cualquiera de las dos); (3) desplegar; (4) cambiar el uso de firma/canje a la nueva; (5) confirmar en métricas que nadie usa la vieja; (6) quitar la vieja del setting y revocar en el proveedor. El código que lo permite: la verificación itera sobre la lista de secretos válidos (un secreto = un lock-in de despliegue coordinado). - En el orquestador/KMS (Secrets Manager/Vault): la imagen Docker es un artefacto que se exporta/comparte/filtra (registros públicos,
docker save); el secreto baked en imagen vive en capas para siempre. El entorno del runtime (o fetch de KMS al arrancar) mantiene el secreto fuera del artefacto.
Ejercicio 3 — RGPD
- Con volumen bajo (<100 reservas por usuario): JSON directo en la respuesta es correcto (la 14: idempotente). Si el histórico fuese enorme: 202 + job + download firmado (la 01: 202 Accepted). Decisión por volumen esperado, documentada.
- Anonimización en
transaction.atomic(): email →f"deleted-{uuid}@invalid", name → "Usuario eliminado", state → DELETED, refresh tokens blacklisted, MFA borrada. Reservas/pagos intactos (obligación fiscal + auditoría). - MFA: borrada (no la necesita una cuenta muerta). Tokens: revocados (blacklist). Organizador: si tiene eventos vivos → bloquear el borrado automático y forzar transferencia de eventos a otro organizador (o cancelación): el flujo manual con soporte es honesto; la FK PROTECT de la 00b ya lo señala.
Ejercicio 4 — Audit log
- Append-only en la app: el modelo no expone update/delete y (más fuerte) en BD:
REVOKE UPDATE, DELETE ON audit_log FROM app_user;— la BD lo garantiza aunque haya bug en el código. SELECT * FROM audit_log WHERE action = 'role.change' AND created_at >= '2026-03-01' AND created_at < '2026-04-01' ORDER BY created_at;— con actor y before/after en JSONB: la respuesta al incidente en una query (la 45 añade req_id).
Ejercicio 5 — Minimización
- Típicos en el proyecto de clase:
fecha_nacimiento"por si acaso" (fuera: no es necesario para vender),avatar_urlsin uso (fuera o justificado), dirección completa para entradas electrónicas (solo si envías físicamente). El Art. 5: adecuación, minimización — cada campo con su finalidad escrita. - Retención propuesta: PENDING expiradas → anonimizar a los 30 días (el asiento vuelve al pool hace tiempo); tokens de reset → 1h ya en el TTL; logs de acceso → 90 días (seguridad) con muestreo a largo plazo anonimizado. El job de purga (31) consulta por fecha y anonimiza en lotes transaccionales.
Resumen del profesor
- Secretos: fuera del artefacto, rotación dual sin downtime, escáner en CI.
- Rate limit atómico en Redis: la concurrencia se resuelve donde viven los datos, otra vez.
- RGPD del desarrollador: minimiza, retén con política, export y olvido implementados (anonimizar ≠ borrar el dinero).
- Audit log append-only: la diferencia entre "creo que nadie tocó nada" y "aquí está el registro".
Cierre del módulo de seguridad. Después: Lección 24 — SOLID e inyección de dependencias (Módulo de arquitectura).