Tema 6

6. A04: Insecure Design y fallas de lógica de negocio

No todas las vulnerabilidades nacen de un error de sintaxis, una mala validación o una librería insegura. En muchos casos, el problema ya estaba presente antes de escribir el código: la aplicación fue pensada de una forma que permite abuso, fraude o exposición porque su diseño nunca contempló adecuadamente el comportamiento hostil.

Objetivo Entender cuándo el problema está en el diseño
Enfoque Lógica de negocio, abuso y arquitectura segura
Resultado Diferenciar fallas de código de fallas estructurales

6.1 Introducción

Muchos equipos asocian seguridad únicamente con bugs técnicos: inyecciones, XSS, sesiones débiles o errores de configuración. Sin embargo, una aplicación puede estar razonablemente bien programada y aun así ser insegura porque su diseño de base permite comportamientos abusivos, privilegios inconsistentes, flujos peligrosos o ausencia de controles donde eran necesarios desde el principio.

OWASP incorpora Insecure Design para destacar precisamente este problema. La vulnerabilidad no aparece solo porque alguien olvidó filtrar una entrada. Aparece porque el sistema fue concebido sin controles adecuados para su contexto, su lógica de negocio o su nivel de riesgo.

Este tema es importante porque obliga a cambiar la mirada: en seguridad no basta con revisar el código; también hay que revisar qué decisiones se tomaron al definir el producto, los roles, los procesos y la arquitectura.

6.2 Qué es Insecure Design

Insecure Design describe debilidades que provienen de decisiones de diseño inseguras o insuficientes. Son problemas estructurales del sistema que no se resuelven solamente "parcheando" líneas de código, porque la falla está en cómo fue pensado el comportamiento permitido.

En otras palabras, la aplicación puede implementar correctamente un diseño equivocado.

Ejemplos conceptuales:

  • Una función de transferencia no tiene límites ni validaciones de riesgo.
  • Un flujo de descuentos permite combinaciones abusivas por diseño.
  • Un sistema administrativo permite acciones destructivas sin confirmación ni doble control.
  • Una API expone operaciones masivas a roles que no deberían tener ese alcance.

6.3 Diseño inseguro versus implementación insegura

Distinguir estas dos categorías es clave.

Problema Pregunta central Ejemplo
Implementación insegura ¿El diseño era correcto pero fue mal codificado? Validación ausente, consulta concatenada, cookie mal configurada
Diseño inseguro ¿El sistema fue concebido sin controles adecuados? Flujo de negocio abusable aunque el código haga exactamente lo que se pidió

En la práctica pueden coexistir ambos problemas, pero la remediación no es la misma. Un bug de implementación puede corregirse localmente; un diseño inseguro suele exigir revisar reglas, procesos y supuestos de negocio.

6.4 Por qué esta categoría es tan difícil

Las fallas de diseño suelen ser más difíciles de detectar que las vulnerabilidades técnicas clásicas porque no siempre dejan errores visibles ni firmas obvias. Muchas veces la aplicación se comporta exactamente como fue pensada, solo que ese pensamiento no contempló abuso ni escenarios hostiles.

Además, estas fallas requieren entender:

  • El negocio.
  • Los procesos reales de usuarios y operadores.
  • Los activos críticos.
  • Los incentivos del atacante.
  • Las relaciones entre roles, estados y privilegios.

No basta con saber HTTP o leer código. También hay que razonar sobre cómo se puede explotar la lógica del sistema.

6.5 Qué son las fallas de lógica de negocio

Una falla de lógica de negocio ocurre cuando una funcionalidad válida puede usarse de forma abusiva o inesperada para producir un resultado no deseado. El problema no es necesariamente técnico en sentido clásico, sino funcional: el sistema permite una combinación de acciones que el negocio no debería aceptar.

Ejemplos comunes:

  • Aplicar múltiples cupones donde solo uno debería ser válido.
  • Modificar el precio final desde un cliente manipulando parámetros.
  • Repetir operaciones de crédito o devolución sin controles de estado.
  • Completar pasos fuera de secuencia y obtener un beneficio no previsto.

6.6 Casos de abuso versus casos de uso

Los equipos de producto y desarrollo suelen trabajar con casos de uso: qué quiere hacer el usuario legítimo y cómo debe responder el sistema. Desde seguridad, eso es necesario pero insuficiente. También hay que trabajar con casos de abuso.

Un caso de abuso pregunta:

  • ¿Cómo podría un usuario manipular este flujo para obtener más de lo debido?
  • ¿Qué pasaría si automatiza miles de intentos?
  • ¿Qué ocurre si modifica el orden de pasos?
  • ¿Puede ejecutar esta acción fuera del contexto esperado?
  • ¿Puede forzar estados inconsistentes?
Diseñar de forma segura implica pensar no solo cómo debe usarse el sistema, sino también cómo podría abusarse.

6.7 Ejemplos de diseño inseguro en aplicaciones web

  • Proceso de recuperación de cuenta basado en datos fáciles de adivinar.
  • Panel interno con funciones críticas sin separación de tareas.
  • Compra online que permite recalcular importes del lado cliente.
  • API que expone acciones masivas sin límites ni aprobaciones.
  • Flujo financiero sin confirmación adicional para operaciones de alto riesgo.
  • Sistema de cupones o puntos que admite acumulaciones no previstas.
  • Descarga de archivos sensibles sin trazabilidad ni vencimiento.

En todos estos casos, el problema no se arregla solo escapando caracteres o activando HTTPS. El modelo de funcionamiento requiere revisión.

6.8 Falta de límites y controles de negocio

Una señal frecuente de diseño inseguro es la ausencia de límites adecuados. Muchas aplicaciones permiten ejecutar acciones válidas sin restricción de volumen, frecuencia, alcance o contexto.

Ejemplos:

  • Intentos ilimitados de recuperación de contraseña.
  • Transferencias sin monto máximo o sin revisión adicional.
  • Creación masiva de recursos sin rate limiting ni cuotas.
  • Exportaciones completas de datos sin segmentación ni justificación.

Cuando el diseño omite estos límites, el atacante puede abusar de una función legítima sin necesidad de romper técnicamente la aplicación.

6.9 Confiar demasiado en el usuario o en el cliente

Muchas fallas de diseño aparecen cuando el sistema asume que el usuario actuará de buena fe o que el cliente enviará datos coherentes. Ese supuesto es incorrecto en seguridad.

Señales típicas:

  • Importes, descuentos o roles enviados por el frontend y aceptados sin recalcular.
  • Estados del proceso controlados por parámetros manipulables.
  • Acciones críticas dependientes de valores que el cliente puede alterar.
  • Falta de verificación server-side de reglas de negocio importantes.

6.10 Diseño inseguro y privilegios excesivos

A veces el problema no está en que una función esté expuesta, sino en que demasiados roles pueden usarla. Cuando el diseño de permisos es demasiado amplio, la aplicación multiplica la superficie de abuso.

Preguntas clave:

  • ¿Realmente este rol necesita esta capacidad?
  • ¿La acción tiene impacto suficiente como para requerir doble control?
  • ¿Hay separación entre operación normal y funciones críticas?
  • ¿Se puede limitar alcance por contexto, unidad o propietario?

Esto conecta Insecure Design con Broken Access Control, pero aquí el problema nace incluso antes de la implementación concreta: la decisión de permisos ya era demasiado permisiva.

6.11 Qué es una arquitectura segura por diseño

Diseñar de forma segura significa tomar decisiones tempranas que reduzcan exposición, limiten impacto y contemplen abuso antes de que el sistema esté construido. No significa predecir todo, pero sí incorporar principios que hagan más difícil el compromiso.

Algunos principios habituales:

  • Mínimo privilegio.
  • Negación por defecto.
  • Separación de responsabilidades.
  • Validación del lado servidor.
  • Defensa en profundidad.
  • Seguridad proporcional al riesgo de la función.

6.12 Modelado de amenazas

Una de las herramientas más útiles para prevenir diseño inseguro es el modelado de amenazas. Consiste en analizar el sistema antes o durante su construcción para identificar activos críticos, superficies de ataque, actores relevantes y posibles formas de abuso.

El modelado de amenazas busca responder preguntas como:

  • ¿Qué recursos son más valiosos o sensibles?
  • ¿Quiénes interactúan con el sistema y con qué privilegios?
  • ¿Qué daño produciría una acción no autorizada o automatizada?
  • ¿Qué partes del flujo podrían abusarse aunque el usuario esté autenticado?
  • ¿Dónde conviene aplicar controles más fuertes?

6.13 Diseñar para el peor caso razonable

Una buena práctica de seguridad consiste en preguntarse qué pasa si un usuario intenta aprovechar sistemáticamente el flujo para obtener ventaja. Esto no significa diseñar paranoicamente todo, sino ajustar controles al valor y al riesgo de cada función.

Ejemplos:

  • Si una operación mueve dinero, debería existir validación reforzada y trazabilidad.
  • Si una acción expone muchos datos, deberían existir límites de exportación y control de rol.
  • Si un proceso impacta a terceros, quizás necesite aprobación o doble verificación.

6.14 Controles compensatorios y defensa en profundidad

Un diseño seguro no depende de una única barrera. Incluso si una función necesita ser flexible, se pueden incorporar capas adicionales que reduzcan abuso.

  • Confirmaciones adicionales en operaciones sensibles.
  • Rate limiting y detección de automatización.
  • Revalidación del estado del objeto antes de ejecutar acciones.
  • Monitoreo de patrones anómalos.
  • Alertas y revisión humana en eventos de alto impacto.

Esto es especialmente importante cuando el negocio exige cierta apertura o agilidad operacional.

6.15 Insecure Design y APIs

Las APIs suelen ser especialmente sensibles a fallas de diseño porque exponen operaciones directas y consumibles por automatización. Si el diseño no contempla límites, granularidad de permisos, consistencia de estados o protección frente a abuso, el problema escala con rapidez.

Algunos riesgos frecuentes:

  • Operaciones masivas sin justificación ni límites.
  • Exposición de datos más amplia de lo necesario.
  • Acciones destructivas sin controles contextuales.
  • Flujos complejos reducidos a llamadas directas sin validaciones intermedias.

6.16 Señales de que puede haber un problema de diseño

Durante una revisión, hay ciertas preguntas que suelen revelar problemas estructurales:

  • ¿El equipo puede explicar claramente por qué cada control existe?
  • ¿Hay reglas de negocio críticas que solo vive el frontend?
  • ¿Existen funciones de alto impacto sin pasos adicionales ni límites?
  • ¿Se documentaron roles, estados y transiciones válidas?
  • ¿El sistema fue pensado para usuarios maliciosos o solo para usuarios normales?
  • ¿Se revisaron escenarios de fraude, abuso o automatización?

6.17 Ejemplo conceptual: descuentos y abuso funcional

Imaginemos una tienda online que permite aplicar cupones de descuento. El equipo diseña la funcionalidad para aceptar varios cupones porque cada uno fue pensado para campañas distintas. Nadie analiza qué ocurre si un usuario automatiza combinaciones, reintenta flujos, divide compras o reutiliza descuentos parciales de forma sistemática.

El sistema puede estar perfectamente programado desde el punto de vista técnico y aun así ser inseguro desde negocio. El problema no es un bug sintáctico. El problema es no haber diseñado restricciones, jerarquías o reglas de exclusión adecuadas.

6.18 Ejemplo conceptual: operación sensible sin contexto suficiente

Supongamos un sistema que permite cambiar el correo principal de una cuenta con solo estar autenticado. El flujo no pide reautenticación, no notifica al usuario anterior, no deja espera de confirmación y no verifica señales de riesgo. Técnicamente puede funcionar tal como fue especificado, pero el diseño es débil para una acción de alto impacto.

Ese tipo de decisión puede facilitar toma de cuentas aunque no exista una vulnerabilidad clásica de inyección o XSS.

6.19 Cómo prevenir diseño inseguro

La prevención empieza antes del código y continúa durante todo el ciclo de vida.

  • Identificar activos y funciones críticas desde la etapa de requisitos.
  • Definir claramente roles, límites y transiciones de estado.
  • Trabajar con casos de abuso además de casos de uso.
  • Realizar modelado de amenazas en funcionalidades sensibles.
  • Diseñar controles proporcionales al impacto de cada operación.
  • Validar la lógica de negocio del lado servidor.
  • Incorporar monitoreo y trazabilidad para detectar abuso real.

6.20 El rol de la documentación y de las decisiones explícitas

Muchos problemas de diseño aparecen porque ciertas suposiciones nunca fueron documentadas ni discutidas. Si no queda claro por qué un rol puede hacer algo, por qué un límite tiene cierto valor o qué escenarios fueron considerados, la seguridad queda sujeta a intuiciones cambiantes.

Documentar decisiones importantes ayuda a:

  • Evitar inconsistencias entre equipos.
  • Facilitar revisiones de arquitectura.
  • Detectar huecos en permisos o flujos.
  • Reevaluar riesgos cuando cambia el producto.

6.21 Errores frecuentes en la remediación

  • Agregar controles técnicos superficiales sin revisar la lógica completa.
  • Corregir un caso puntual de abuso y dejar el resto del flujo igual.
  • Asumir que seguridad es tarea exclusiva del desarrollador final.
  • Tratar fallas de negocio como si fueran simples bugs aislados.
  • No revisar impacto sobre APIs, backoffice y procesos administrativos.
  • Ignorar fraude y automatización porque "la función está permitida".
Cuando el problema es de diseño, el parche local rara vez alcanza. Hay que revisar la intención, las restricciones y las decisiones que sostienen la funcionalidad.

6.22 Relación con otras vulnerabilidades

Insecure Design suele actuar como capa profunda que agrava otras categorías:

  • Con Broken Access Control, si los permisos ya fueron definidos de forma demasiado amplia.
  • Con Authentication Failures, si una acción sensible no exige suficiente garantía de identidad.
  • Con SSRF o Injection, si la arquitectura expone capacidades peligrosas sin restricciones.
  • Con Logging Failures, si no hay trazabilidad para detectar abuso funcional sostenido.

Esto muestra que el diseño inseguro no compite con otras vulnerabilidades: muchas veces las explica o las amplifica.

6.23 Qué debes recordar de este tema

  • Una aplicación puede ser insegura aunque el código implemente correctamente un diseño equivocado.
  • Insecure Design se relaciona con decisiones estructurales insuficientes frente al abuso o al riesgo.
  • Las fallas de lógica de negocio suelen permitir fraude o uso indebido de funciones legítimas.
  • Hay que pensar en casos de abuso además de casos de uso.
  • El modelado de amenazas ayuda a anticipar problemas antes de implementarlos.
  • Los controles deben ser proporcionales al impacto de la función.
  • Cuando el problema es de diseño, la remediación suele requerir revisar el flujo completo.

6.24 Conclusión

Insecure Design nos recuerda que la seguridad no empieza en la validación de entradas ni termina en el escaneo de vulnerabilidades. Empieza mucho antes, cuando se decide cómo funcionará el sistema, qué asumirá del usuario y qué controles existirán para evitar abuso, fraude o consecuencias desproporcionadas.

En el próximo tema estudiaremos A05: Security Misconfiguration, donde el problema ya no estará tanto en la lógica del producto como en configuraciones débiles, entornos mal endurecidos y exposición innecesaria de componentes y servicios.