Tema 6
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.
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.
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:
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.
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:
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.
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:
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:
En todos estos casos, el problema no se arregla solo escapando caracteres o activando HTTPS. El modelo de funcionamiento requiere revisión.
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:
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.
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:
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:
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.
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:
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:
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:
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.
Esto es especialmente importante cuando el negocio exige cierta apertura o agilidad operacional.
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:
Durante una revisión, hay ciertas preguntas que suelen revelar problemas estructurales:
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.
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.
La prevención empieza antes del código y continúa durante todo el ciclo de vida.
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:
Insecure Design suele actuar como capa profunda que agrava otras categorías:
Esto muestra que el diseño inseguro no compite con otras vulnerabilidades: muchas veces las explica o las amplifica.
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.