Incorporando la seguridad al proceso de desarrollo de software

No es un secreto para nadie que una parte importante de los problemas de seguridad de los sistemas de información tiene su origen en defectos de las aplicaciones que éstos ejecutan. Tampoco lo es que estos defectos, que se manifiestan en forma de vulnerabilidades, se introducen en el software durante su proceso de desarrollo. Lo que a día de hoy no es algo aún suficientemente conocido, es la solución a este problema.

Históricamente, la industria del software ha funcionado usando una dinámica de liberar al mercado productos con un escaso nivel de madurez y se ha ocupado sobre la marcha de corregir los defectos que fueran apareciendo (véase el enfoque de Berkeley frente al del MIT en la entrada de Javier Vela al respecto, ¿Peor es mejor?). La situación actual es algo distinta ya que la capacidad del entorno de encontrar y explotar vulnerabilidades es muy elevada. Por tanto, liberar una aplicación al mercado, especialmente si está destinada a ofrecer servicios al público a través de Internet, sin haber tomado un mínimo de medidas para evitar la aparición de vulnerabilidades, es sin lugar a dudas una invitación al desastre.

La presión por cumplir con el calendario y el presupuesto de proyecto y la exigencia de los usuarios por disponer de nuevas funcionalidades, provocan con frecuencia que la seguridad no esté precisamente en la parte alta de la lista de prioridades de los equipos de desarrollo. Además, la eliminación de vulnerabilidades se suele entender como una tarea de la que alguien se encarga en la fase de testeo al final del ciclo de desarrollo, cuando la fase de programación ha concluido.

Sin embargo, el énfasis que desde distintas organizaciones se está haciendo por incorporar la seguridad al ciclo de desarrollo de software, así como iniciativas en esta línea de grandes corporaciones productoras de software, parece indicar que las tendencias están cambiando. Muchos pensamos hoy que todas las fases del proceso de desarrollo deberían compartir un objetivo: garantizar la seguridad del software.

A pesar de todo, es bastante común que en organizaciones que producen software, no exista ninguna incorporación formal de medidas de seguridad al ciclo de desarrollo. Los motivos son diversos: falta de presupuesto, de concienciación, de conocimiento… La realidad es que en la mayoría de los casos el software se valora fundamentalmente por la funcionalidad que implementa y la calidad del código raramente se considera; hasta que ocurre lo que nadie tuvo en cuenta…

La existencia de defectos de seguridad es hoy por hoy algo inevitable, sin embargo, la incorporación de una serie de medidas al proceso de desarrollo de software, permite reducir el riesgo a unos niveles aceptables. Con este objetivo se puede actuar en distintos puntos del proceso aplicando cada medida en el momento adecuado:

Análisis de requisitos

Resolver problemas de seguridad en un sistema en producción suele ser un proceso muy costoso y en ocasiones, con un alto impacto en el negocio e incluso en la imagen de la organización que ofrece el producto o servicio. Por este motivo, es importante tener en cuenta los controles necesarios para evitar su aparición desde fases tempranas del proceso, considerando los requisitos de seguridad como parte del análisis junto con los requisitos funcionales.

Es importante además no olvidar la consideración de aspectos de conformidad legal que incluyan en el catálogo de requisitos las obligaciones introducidas por regulaciones como la LOPD o la SOX entre otras.

Diseño

El diseño debe considerar aspectos como la reducción al mínimo de la interfaz atacable, así como su protección mediante la introducción de patrones y soluciones adecuadas para evitar la aparición de vulnerabilidades conocidas. En este punto es referencia obligada alguna de las guías existentes (las recomendaciones de OWASP por ejemplo) que recogen las vulnerabilidades más frecuentes junto con medidas técnicas para evitar su aparición.

Análisis de riegos (Casos de abuso y Modelado de amenazas)

Es frecuente que los analistas especifiquen los requisitos describiendo el comportamiento de un sistema “cuando todo va bien”. Esto suele llevar a una visión funcional del sistema basada en la asunción de que no va a ser objeto de abusos intencionados. Nada más lejos de la realidad, si el sistema va a ser usado, con toda seguridad se abusará de él (voluntaria a involuntariamente). El modelado de amenazas se realiza para determinar si el diseño propuesto mitiga los riesgos identificados y permite a los diseñadores ponerse en el papel del atacante:

  • ¿Qué partes del sistema son más fáciles de comprometer?
  • ¿Cuál es el impacto?

De esta forma las amenazas se identifican y se priorizan. A continuación se comprueba si la amenaza se mitiga mediante la implantación de un control. Si esto no es posible, se cambia el diseño o se asume el riesgo (idealmente, en función del risk appetite definido formalmente por la organización).

Análisis estático de código

En el pasado, el análisis de código se realizaba únicamente de forma manual. Era un proceso que daba buenos resultados cuando lo realizaba un experto, pero suponía un coste muy elevado. Hoy disponemos de herramientas de análisis estático que son capaces de identificar una buena parte de los errores de código por un coste mucho menor que el de un análisis manual.

El uso de estas herramientas es óptimo cuando todos los módulos que componen el software están completos e integrados. El análisis estático se debería realizar como mínimo en cada integración y siempre antes de liberar una nueva versión.

Testeo (o auditoria) de seguridad

Sería estupendo que el análisis estático fuese capaz de identificar todas las vulnerabilidades existentes en el software, pero desgraciadamente esto no es así. Por este motivo es necesaria la introducción de métodos dinámicos de testeo que interactúen con la aplicación como lo haría un atacante (Penetration Testing).

El testeo de seguridad es similar al testeo funcional del software con la diferencia de que en este caso se busca que la aplicación funcione de formas para las que no ha sido diseñada. El testeo funcional acaba (idealmente) cuando cada “feature” ha sido testeada, sin embargo, no es fácil identificar todas las cosas que una aplicación no debería hacer. Por este motivo es importante seguir una aproximación priorizada en la que se puede tomar como criterio la priorización realizada en el modelado de amenazas.

Existen varias herramientas que permiten la automatización del Penn Testing, pero de nuevo en este caso, será necesario contar con las manos de un experto para testear aquellos aspectos que no es posible automatizar.

¿Cómo empezar?

La incorporación de todas estas medidas, especialmente cuando se parte de una situación de poca cultura de seguridad, puede resultar algo abrumadora. Aunque el objetivo final debe ser que el proceso de desarrollo se enriquezca con todas las aportaciones descritas, no es imprescindible que se adopten todas desde el principio para obtener mejoras significativas en la seguridad del software producido.

La modificación del proceso se puede plantear como un proceso de mejora continua, empezando por aquellas medidas que requieren un esfuerzo y nivel de conocimiento y especialización moderado, para ir incorporando el resto según la experiencia y el know-how de la organización vaya creciendo.

Teniendo en cuenta que, especialmente en este caso, algo es mejor que nada, algunas de las medidas presentadas pueden ser adoptadas inicialmente asumiendo un coste reducido y con un retorno importante. El análisis de requisitos de seguridad puede ser la primera de ellas, garantizando así una toma de consciencia de los aspectos de seguridad a implementar. Por otro lado, la implantación de herramientas de análisis estático desde un principio, permite evitar un cantidad importante de errores y potenciales vulnerabilidades con una inversión muy contenida.

En este post se han presentado algunas medidas que tienen que ver directamente con el proceso de producción de software, pero existen algunas más que aplican al entorno de soporte del proceso (separación de entornos, seguridad de los repositorios de información, control de configuración, etc), pero eso da para otra entrada y lo trataremos en una próxima ocasión. Como siempre, pasen un buen fin de semana.

(Fuente de la imagen: OWASP)