← Documentos

Modelo de amenazas (STRIDE)

4. Modelo de amenazas y mitigaciones (STRIDE)

ExpressMX adopta una postura Zero Trust por defecto: ningún componente asume confianza implícita en la red, todos los accesos a datos de cliente se autentican, autorizan y auditan. El modelo se documenta usando STRIDE con una mitigación por categoría.

Última actualización: 2026-05-05


4.1 Capas de seguridad

Capa Responsabilidad Implementación
TLS edge Cifrado en tránsito TLS 1.3 terminado en Vercel, HSTS
JWT auth Identidad del usuario apps/web/src/lib/auth/session.ts, jose con JWT_SECRET ≥ 32 chars
RBAC permisos Autorización por rol y permiso roles_admin, permisos, roles_permisos
RLS Postgres Aislamiento a nivel de fila ALTER TABLE ... ENABLE ROW LEVEL SECURITY
Audit log Trazabilidad y no repudio logs_auditoria, append-only
Break-glass Acceso controlado a PII de cliente pins_soporte_cliente, casos_soporte_abiertos

4.2 Trust boundaries explícitas

  1. Borde móvil ↔ backend. Las apps Expo y la web del cliente envían peticiones a través de Internet. Todo request es validado por el middleware JWT antes de llegar al handler.
  2. Backend ↔ base de datos. DATABASE_URL se inyecta en runtime de Vercel; la conexión TLS pooled apunta al endpoint de Neon. La base es inalcanzable directamente desde Internet.
  3. Admin ↔ PII de cliente. Un admin con permisos no puede consultar datos de un cliente sin un caso break-glass vigente abierto a partir de un PIN generado por el cliente.

4.3 Tabla STRIDE × Mitigación

Categoría STRIDE Amenaza concreta Mitigación implementada Evidencia
Spoofing Cliente se hace pasar por otro usuario en la API JWT HS256 firmado, JWT_SECRET ≥ 32 chars validado al startup; verifyToken rechaza tokens forjados apps/web/src/lib/auth/session.ts líneas 11-15 y 35-42; integración valida token forjado y expirado en apps/web/src/__tests__/integration/auth.test.ts
Tampering Cliente envía campos extra para forzar rol=admin o cliente_id=otro Schemas Zod estrictos con strip silencioso; tests adversariales lo confirman packages/validations/src/__tests__/mobile-register.test.ts ("rechaza rol=admin", strip de id, activo, avatar_url); mobile-orders.test.ts strip de cliente_id, prestador_id
Repudiation Admin niega haber consultado o modificado datos de un cliente logs_auditoria append-only registra cada mutación con actor, recurso y timestamp; casos_soporte_abiertos deja huella del agente que abrió el caso migrations/003_pins_soporte_cliente.sql (tabla casos_soporte_abiertos); patrón logAccion documentado en RBAC Zero Trust
Information Disclosure Cliente A intenta leer recursos del cliente B vía /api/v1/mobile/orders/[id] requireOwner ejecuta SELECT 1 FROM <tabla> WHERE id = $1 AND usuario_id = $2; si no hay fila lanza NotFoundError para no leak de existencia. RLS habilitado en tablas sensibles apps/web/src/lib/auth/guards.ts líneas 73-79; test "email inexistente → 401 (no leak de existencia)" en auth.test.ts
Denial of Service Atacante envía paginación absurda (limit=1000000) o cursor enorme Schemas Zod imponen limit ∈ [1,50], cursor ≤ 256 chars, notas ≤ 1000 chars, password ≤ 128 chars; rate limiting en edge Vercel packages/validations/src/__tests__/common.test.ts ("rechaza limit muy grande (DoS)", "rechaza cursor con tamaño excesivo (DoS)")
Elevation of Privilege Cliente intenta acceder a endpoints de prestador o admin requireRole valida session.rol contra lista permitida y retorna 403; rol Zero Trust lector_basico para nuevos admins; super_admin requiere asignación explícita de cada permiso migrations/004_rbac_permisos_zero_trust.sql líneas 62-70 (lector_basico); test "cliente intentando GET jobs → 403 FORBIDDEN" en provider-jobs.test.ts

4.4 Mecanismo break-glass (Zero Trust)

El modelo prohíbe que un agente de soporte navegue listas de clientes. El flujo controlado es:

  1. El cliente genera un PIN desde su app móvil; el PIN se almacena hasheado en pins_soporte_cliente y expira en 15 minutos (migrations/003_pins_soporte_cliente.sql).
  2. El cliente entrega el PIN al agente por canal acordado.
  3. El agente lo introduce en la consola de soporte; la apertura crea una fila en casos_soporte_abiertos con agente_id, cliente_id, pin_id, expira_en (4 horas) y abierto_en.
  4. El scope de las consultas del agente sobre datos del cliente queda atado al caso vigente; al cerrar o expirar el caso se pierde el acceso.
  5. La acción de apertura y cierre queda persistida y disponible para auditoría.

Permisos asociados (introducidos en migración 004):

4.5 Hardening adicional

4.6 Gaps conocidos y trabajo pendiente

↑ Volver arriba