Módulo 4 · Autenticación y seguridad

Lección 23 — Secretos, rate limiting y RGPD

Gestión de secretos, límites de peticiones y protección de datos personales.

Publicada
En esta lección
  1. Objetivos
  2. 1. Secretos: el ciclo de vida
  3. 2. Rate limiting: token bucket con Redis
  4. 3. RGPD para el desarrollador (lo que toca tu código)
  5. 4. Logs de auditoría (la puntada que une)
  6. Autoevaluación

Stack: DRF + Redis · Proyecto: TicketFlow Estado: Publicada — cierre del módulo de seguridad Prerrequisito: Lección 22 — OWASP


Objetivos

  1. Gestionar secretos sin que acaben en Git, logs ni imágenes de Docker (jerarquía de entornos y rotación).
  2. Implementar rate limiting real (token bucket con Redis) en login y checkout.
  3. Aplicar RGPD a TicketFlow: base legal, minimización, derechos (export/borrado) y logs de auditoría.

1. Secretos: el ciclo de vida

  • Nunca en Git (la 05): .env fuera, env.example dentro. El historial filtrado se repara rotando, no borrando.
  • Jerarquía de entorno: dev (valores dummy), staging (secretos de test), prod (KMS/vault: AWS Secrets Manager, HashiCorp Vault, o al mínimo: variables de entorno del orquestador — jamás baked en la imagen Docker: la imagen se filtra).
  • Rotación: toda credencial tiene fecha de caducidad en tu inventario (SECRET_KEY de Django: rota con plano de migración de sesiones; claves de pasarela: rotación dual — publicar nueva, migrar, revocar vieja). La rotación exitosa es la que puedes hacer sin downtime: diseña para eso.
  • Acceso de personas: nadie guarda secretos de prod en su máquina; acceso temporal, auditado (25/56). git-secrets/trufflehog en CI para prevenir commits de secretos.

2. Rate limiting: token bucket con Redis

El límite protege: login (brute force, 20), checkout (bots comprando todo — el caso I4-adjacente de TicketFlow), API pública (abuso). Algoritmo token bucket: el usuario tiene N tokens que se regeneran a ritmo R; cada request gasta uno; sin token → 429 con Retry-After.

python
def allow(key: str, capacity: int, refill_per_min: int) -> bool:
    now = time.time()
    pipe = redis_pipeline()
    data = pipe.hgetall(key).execute()          # tokens, last_refill
    tokens = min(capacity, float(data.get(b"tokens", capacity)))
    elapsed = now - float(data.get(b"last", now))
    tokens = min(capacity, tokens + elapsed * refill_per_min / 60)
    if tokens < 1:
        pipe.hset(key, mapping={"tokens": tokens, "last": now}); pipe.expire(key, 3600)
        return False
    pipe.hset(key, mapping={"tokens": tokens - 1, "last": now}); pipe.expire(key, 3600)
    return True

Producción: hazlo atómico con un script Lua (evita la raza entre HGETALL y HSET — la 10/12 aplicada a Redis) o usa la librería django-ratelimit. Claves: por IP para anónimos, por usuario para autenticados, por endpoint sensible (login, checkout) con límites más duros. Y respuesta honesta: 429 + Retry-After + log del evento (46): un bot bloqueado es información, no ruido.

3. RGPD para el desarrollador (lo que toca tu código)

  • Base legal y minimización: solo datos necesarios para vender entradas: nombre, email, y los de facturación. El "fecha de nacimiento por si acaso" NO se recoge. Menos datos = menos responsabilidad.
  • Finalidad y retención: las reservas se retienen (fiscal), los carritos abandonados NO: job de purga de PENDING expiradas viejas (anónimas) — la retención es una decisión de datos, documentada.
  • Derecho de acceso/export (Art. 15): endpoint de export del usuario (su perfil + reservas + pagos, JSON o CSV) — autenticado, su propio dato, la 14 garantiza idempotencia del export.
  • Derecho al olvido (Art. 17): borrar/no: las ventas tienen obligación fiscal → anonimización (email → hash irreversibles, nombre → "eliminado"), mantener el registro contable. Nunca DELETE de pagos (auditoría, la 08).
  • Consentimiento: marketing separado de la operación (checkbox no obligatorio), revocable en un clic.
  • Procesadores: la pasarela y el proveedor de email son encargados de tratamiento: DPA firmado (papel del negocio; tu parte: saber qué datos viajan a cada uno).

4. Logs de auditoría (la puntada que une)

El audit log registra QUIÉN hizo QUÉ CUÁNDO sobre qué recurso, inmutable: cambios de rol (21), reembolsos, cambios de evento, accesos a datos de usuario. Tabla append-only (sin UPDATE/DELETE por diseño) + retención definida. Es lo que convierte "creemos que nadie tocó el pago" en "aquí está el registro" (la 56 lo formaliza para SOC2).


Autoevaluación

  1. Filtró tu repo un secreto de la pasarela hace un mes: ¿cuál es la única reparación real y cómo se hace sin downtime?
  2. ¿Por qué el token bucket necesita atomicidad (Lua) y qué bug produce la versión con HGET/HSET separados?
  3. ¿Por qué el rate limit del login es por usuario+IP y no solo por IP? ¿Qué ataque evita el límite por usuario?
  4. Un usuario pide borrarse: ¿por qué no DELETE de sus pagos y qué se hace exactamente con sus datos?
  5. ¿Qué tres datos NO debe pedir TicketFlow y por qué (minimización)?

Continúa con los ejercicios. Las solutions.md solo tras intentarlo.