Problema de diseño tienda online
Tienda online reporta problema critico de arquitectura de software y seguridad
Ejercicio típico de entrevista estilo ticket de Arquitectura de software y seguridad para un perfil base, con respuestas y planteos modelo.
Planteo del problema
Durante el fin de semana se realizó el despliegue a producción de nuestra tienda online. Recibimos varios reportes y fallas detectadas en nuestro sistema de monitoreo: los usuarios pueden completar compras de productos que no pertenecen a su propio carrito, ya que corresponden a otro usuario. Se registraron varios casos reportados con este mismo patrón.
Los status codes que recibimos no son debuggeables porque la mayoría de las respuestas devuelven un 200, incluso en casos donde la operación no debería haberse permitido. En algunos casos puntuales, la respuesta sí es un 401 Unauthorized.
No contamos con un diagrama arquitectónico que refleje cómo está compuesto nuestro sistema, pero sí podemos detallar los componentes y las integraciones con las que cuenta:
- Componente de autenticación integrado con un proveedor externo OIDC (Google Provider).
- Integración con proveedor externo para procesar pagos de los productos.
- Componente de monitoreo en nuestros servidores.
- Load Balancer y réplicas de los servidores.
Contamos con las capacidades de codeaseguro para resolver este inconveniente lo más pronto posible.
Análisis de la problemática
Se detallan los ítems detectados al analizar la problemática actual del sistema de tienda online:
- No cuenta con documentación de APIs.
- El problema no es de carga — el sistema cuenta con Load Balancer y réplicas, así que la disponibilidad no está comprometida. El problema es de lógica de acceso: el servidor verifica que el usuario esté logueado (autenticación), pero nunca verifica si ese recurso específico le pertenece a ese usuario (autorización). Son dos preguntas distintas: “¿sos vos?” vs. “¿esto es tuyo?” — y el sistema solo responde la primera.
- Se pudo reproducir el problema simplemente cambiando el ID de producto en la request de compra (
/productos/1023→/productos/1024), y el sistema procesó la operación sin validar que ese producto perteneciera al carrito del usuario autenticado. - La inconsistencia en los status codes (200 en la mayoría de los casos, 401 en algunos) es en sí misma un hallazgo: enmascara fallas de autorización como si fueran operaciones exitosas, lo que dificulta detectar el abuso desde el sistema de monitoreo y retrasa la respuesta ante incidentes.
Solución propuesta
Componente que se agrega: capa de autorización explícita
En cada request que accede a un recurso específico (un producto, un pedido, un dato), el servidor valida: “el ID de usuario autenticado, ¿es dueño de este recurso ID?” antes de devolver la respuesta. Esto puede vivir como una capa intermedia (middleware) que se aplica de forma consistente a todos los endpoints, en vez de que cada desarrollador se acuerde de chequearlo a mano en cada uno.
Por qué se usa acá: sin esta capa, cualquier endpoint que reciba un ID por parámetro es vulnerable — no importa cuán robusta sea la infraestructura de abajo.
Capa de seguridad — nombre técnico para dar contexto
Esto es una vulnerabilidad muy común y catalogada: IDOR (Insecure Direct Object Reference) — está en el Top 10 de OWASP. La mitigación es control de acceso a nivel de objeto: nunca confiar en que el ID que llega en la URL/request es válido para ese usuario; siempre validarlo contra la sesión autenticada del lado del servidor.
Como recomendación adicional, los status codes también deben corregirse: toda operación no autorizada debe responder consistentemente con 401 (no autenticado) o 403 (autenticado pero sin permiso sobre ese recurso) — nunca con 200. Esto no solo es una cuestión de estándar HTTP, sino de observabilidad: sin códigos correctos, el sistema de monitoreo no puede detectar estos intentos.
Diagrama arquitectura propuesta
flowchart LR
subgraph external["Proveedores externos"]
direction TB
oidc["OIDC Provider<br/>(Google)"]
payment["Proveedor de pagos"]
end
subgraph arq["Arquitectura Propuesta"]
direction LR
users["<b>Users</b>"]
web["Web Tienda Online"]
lb["Load Balancer"]
subgraph servers["Réplicas de servidores"]
direction TB
servidor_a["Servidor A"]
servidor_b["Servidor B"]
servidor_c["Servidor C"]
end
authz["Capa de Autorización<br/>(middleware)"]
db[("Base de datos")]
monitoring["Monitoreo"]
users --> web
web --> lb
lb --> servidor_a
lb --> servidor_b
lb --> servidor_c
servidor_a --> authz
servidor_b --> authz
servidor_c --> authz
authz --> db
end
web -.autenticación.-> oidc
servers -.procesar pago.-> payment
servers -.métricas / logs.-> monitoring
style authz fill:#256B2D,stroke:#ADFFB7,color:#fff
style db fill:#256B2D,stroke:#ADFFB7,color:#fff
style oidc fill:#1E3A5F,stroke:#6BA3D6,color:#fff
style payment fill:#1E3A5F,stroke:#6BA3D6,color:#fff - #arquitectura-software
- #appsec
- #entrevista
- #owasp