Los malos patrones de codificación pueden provocar grandes problemas de seguridad... ¿por qué los fomentamos?

Publicado Nov 03, 2022
por el doctor Matias Madou
ESTUDIO DE CASO

Los malos patrones de codificación pueden provocar grandes problemas de seguridad... ¿por qué los fomentamos?

Publicado Nov 03, 2022
por el doctor Matias Madou
Ver recurso
Ver recurso

Una versión de este artículo apareció en DZone. Ha sido actualizada y sindicada aquí.

Durante lo que parece una eternidad en este momento, hemos hablado de "cambiar a la izquierda" en el SDLC, teniendo en cuenta las mejores prácticas de seguridad desde el inicio del desarrollo de software. DevSecOps fue un gran salto adelante, en gran parte debido al énfasis en la responsabilidad compartida de la seguridad, y el poder de un desarrollador consciente de la seguridad para frustrar las vulnerabilidades comunes mientras escriben el código. 

También sabemos -de nuevo, desde hace siglos- que el tipo de formación en código seguro que se elige para involucrar y capacitar a los desarrolladores marca la diferencia. Las soluciones de bajo esfuerzo motivadas únicamente por el cumplimiento de la normativa no construyen las mentes brillantes de la seguridad del futuro, y la mayoría de los profesionales de la concienciación sobre la seguridad lo han comprobado. Lo mejor es un aprendizaje dinámico y contextualmente relevante, pero es fundamental que se comprendan los matices. 

Si queremos tener una oportunidad de luchar contra los actores de las amenazas -y siempre tienen una ventaja sobre una organización- los desarrolladores necesitan un entorno de formación integral, con un aprendizaje en capas que construya continuamente habilidades impregnadas de las mejores prácticas.

Las medidas de seguridad defensivas impulsadas por los desarrolladores no son una victoria automática.

Nuestra filosofía gira en torno al desarrollador como elemento central de una estrategia de seguridad preventiva, desde el nivel de código hacia arriba. Esto es un hecho, y los desarrolladores capacitados en seguridad proporcionan el camino más fácil para frustrar los tipos de errores de seguridad comunes que son evidentes en los patrones de codificación pobres (como Log4Shell, como un ejemplo reciente y devastador).

Sin embargo, las técnicas defensivas que podemos emplear para capacitar a los desarrolladores varían, aunque puedan existir con razón en el mismo cubo de formación. 

Por ejemplo, imagina que te dijeran cómo hornear una tarta, utilizando únicamente indicaciones basadas en lo que no hay que hacer. "No lo hornees demasiado", y "no te olvides de los huevos" deja abierta la interpretación, y un enorme potencial de errores que tendrán un resultado final apto para ¡Lo he clavado!. Lo mismo ocurre con la educación en seguridad defensiva; lo que no hay que hacer es una parte muy limitada de la conversación, y no ofrece ningún consejo práctico para actuar realmente con una mentalidad defensiva. Se puede decir a los desarrolladores "no configuren mal esa API", pero si no se entiende lo que constituye una configuración correcta y segura, hay mucho margen de error.

Los desarrolladores no tendrán un impacto positivo en la reducción de la vulnerabilidad sin una comprensión fundamental de cómo funcionan las vulnerabilidades, por qué son peligrosas, qué patrones las causan y qué patrones de diseño o codificación las solucionan en un contexto que tiene sentido en su mundo. Un enfoque de andamiaje permite que las capas de conocimiento ofrezcan una imagen completa de lo que significa codificar de forma segura, defender una base de código y ser un desarrollador consciente de la seguridad. Y sí, parte de ese aprendizaje por capas debe dedicarse a la ofensiva, y a entender la mentalidad de un atacante; esto es fundamental para perfeccionar las habilidades de pensamiento lateral, que son inestimables en el modelado de amenazas y la estrategia defensiva. 

Reforzar los malos patrones de codificación es una trampa que no podemos ignorar.

Una desafortunada realidad con algunos métodos de aprendizaje para desarrolladores es que la parte "defensiva" -incluso cuando la formación está estructurada con técnicas ofensivas- puede reforzar los malos hábitos, incluso si técnicamente están validando la seguridad del código. 

La producción de código de alta calidad debería ser la línea de base en todo el desarrollo de software, pero la definición de "calidad" todavía parece ser objeto de debate. La realidad es que el código inseguro no puede considerarse de calidad, aunque sea funcional y bonito. Lo mejor es que el código seguro tampoco es inherentemente de alta calidad. En otras palabras, unos patrones de codificación deficientes pueden solucionar un problema de seguridad, pero al hacerlo, introducir otro, o potencialmente romper el software por completo. 

Veamos un ejemplo de código de baja calidad en forma de corrección de la autenticación rota, así como la versión más segura para las mejores prácticas:

utilizando System;
usando System.Collections.Generic;
usando System.Linq;
usando System.Threading.Tasks;
usando Microsoft.AspNetCore.Authorization;
usando Microsoft.AspNetCore.Http;
usando Microsoft.AspNetCore.Mvc;
namespace BadFixesAPI.Controllers
{
    [Ruta("api/[controlador]")]
    [ApiController]
    public class AlertsController : ControllerBase
    {
        private DatabaseContext context = new DatabaseContext();
        [HttpGet(Name = "GetAlerts")]
        // Does not ensure that the user is authenticated 
        public IEnumerable<Alert> Get()
        {
            return context.GetAlerts();
        }
        [HttpGet(Name = "GetAlerts")]
        // Ensures that the user is authenticated, but does not check any roles
        [Authorize()]
        public IEnumerable<Alert> GetBadFix()
        {
            return context.GetAlerts();
        }
        [HttpGet(Name = "GetAlerts")]
        // Ensures that the user is authenticated, AND that they have the "Administrator" role
        [Authorize(Roles = "Administrador")]
        public IEnumerable<Alert> GetGoodFix()
        {
            return context.GetAlerts();
        }
    }
}

En el primer fragmento, no hay ninguna comprobación para verificar que el usuario está autenticado, lo cual es lo más inseguro que puede haber. El segundo, aunque es mejor en cuanto a que realiza una comprobación de autenticación, no investiga los roles asignados ni si los permisos son lo suficientemente altos para la información solicitada. El tercero comprueba tanto la autentificación del usuario como que tenga asignado el rol de "Administrador". En una época en la que el control de acceso con mínimos privilegios debería ser la norma en la mayoría de los casos, es fundamental que se establezcan y comprueben los roles para garantizar que sólo se pueda acceder a la información cuando sea necesario. 

La máxima prioridad de los desarrolladores es crear funcionalidades, y aunque la seguridad no se deja de lado intencionadamente, no tienen necesariamente las habilidades necesarias para evitar los malos patrones de codificación que conducen a errores de seguridad, y el punto de referencia de un buen ingeniero rara vez incluye la destreza en la codificación segura. Fomentamos indirectamente esos malos hábitos si las características son lo suficientemente impresionantes, y es esta mentalidad la que tiene que cambiar. El problema es que la forma en que algunas vías de aprendizaje fomentan la corrección práctica del código también refuerza potencialmente el código que es seguro, pero de calidad inferior. Al aplicar un binario "sí esto es seguro / no esto no es seguro" assessment, en lugar de profundizar en si es realmente el mejor enfoque para resolver el error y mantener la integridad del software, hay demonios en los detalles que pasan desapercibidos. 

Sin llevar a los desarrolladores a través de todo el proceso para obtener una visión completa de la codificación segura, este enfoque perpetúa los mismos problemas que intenta resolver. Imagínese que todos obtuviéramos nuestro carné de conducir basándonos únicamente en nuestra capacidad para conducir un vehículo hasta un destino; un aprobado aunque nos hayamos saltado semáforos en rojo, hayamos atravesado un seto y nos hayamos saltado por poco a un peatón que cruzaba la calle para llegar allí. Completamos la meta, pero lo que más importa es el trayecto que hicimos para llegar a ella. 

Hay que capacitar a los desarrolladores para que se preocupen más por crear software seguro.

El desarrollador moderno tiene que mantener un montón de platos girando, y no es de extrañar que encuentren la formación en seguridad aburrida, especialmente cuando no se implementa teniendo en cuenta su día de trabajo, y les aleja de sus plazos y prioridades. También es completamente injusto cambiar sus KPI para incluir un énfasis en la codificación segura, cuando no tienen las habilidades construidas a partir de oportunidades de aprendizaje regulares y adecuadas y herramientas complementarias. Sin embargo, no se puede exagerar la importancia del desarrollo de software seguro, y conseguir que los desarrolladores se pongan de acuerdo es crucial. 

Como antiguo desarrollador, por lo general, queremos hacer un gran trabajo, y ser visto como un corte por encima de los demás en términos de producción de calidad es muy motivador. Incentivar a los desarrolladores para que se comprometan con el desarrollo continuo de habilidades de seguridad es una obviedad, y deben ser recompensados por reconocer la importancia de la seguridad a nivel de código. Los programas de campeones de seguridad, las recompensas por errores y los hackathons pueden ser grandes oportunidades para construir una cultura de seguridad positiva, y aquellos que se arremangan y participan deben obtener el botín.

Ver recurso
Ver recurso

Autor

Doctor Matias Madou

Matías es un investigador y desarrollador con más de 15 años de experiencia práctica en seguridad de software. Ha desarrollado soluciones para empresas como Fortify Software y su propia empresa Sensei Security. A lo largo de su carrera, Matías ha dirigido múltiples proyectos de investigación sobre seguridad de aplicaciones que han dado lugar a productos comerciales y cuenta con más de 10 patentes en su haber. Cuando está lejos de su escritorio, Matias ha servido como instructor para la formación de seguridad de aplicaciones avanzadas courses y regularmente habla en conferencias mundiales como la Conferencia RSA, Black Hat, DefCon, BSIMM, OWASP AppSec y BruCon.

Matías es doctor en Ingeniería Informática por la Universidad de Gante, donde estudió la seguridad de las aplicaciones mediante la ofuscación de programas para ocultar el funcionamiento interno de una aplicación.

¿Quieres más?

Sumérjase en nuestras últimas ideas sobre codificación segura en el blog.

Nuestra amplia biblioteca de recursos tiene como objetivo potenciar el enfoque humano de la mejora de la codificación segura.

Ver blog
¿Quieres más?

Obtenga las últimas investigaciones sobre la seguridad impulsada por los desarrolladores

Nuestra amplia biblioteca de recursos está repleta de recursos útiles, desde libros blancos hasta seminarios web, que le ayudarán a iniciarse en la codificación segura orientada a los desarrolladores. Explórela ahora.

Centro de recursos

Los malos patrones de codificación pueden provocar grandes problemas de seguridad... ¿por qué los fomentamos?

Publicado Nov 03, 2022
Por el doctor Matias Madou

Una versión de este artículo apareció en DZone. Ha sido actualizada y sindicada aquí.

Durante lo que parece una eternidad en este momento, hemos hablado de "cambiar a la izquierda" en el SDLC, teniendo en cuenta las mejores prácticas de seguridad desde el inicio del desarrollo de software. DevSecOps fue un gran salto adelante, en gran parte debido al énfasis en la responsabilidad compartida de la seguridad, y el poder de un desarrollador consciente de la seguridad para frustrar las vulnerabilidades comunes mientras escriben el código. 

También sabemos -de nuevo, desde hace siglos- que el tipo de formación en código seguro que se elige para involucrar y capacitar a los desarrolladores marca la diferencia. Las soluciones de bajo esfuerzo motivadas únicamente por el cumplimiento de la normativa no construyen las mentes brillantes de la seguridad del futuro, y la mayoría de los profesionales de la concienciación sobre la seguridad lo han comprobado. Lo mejor es un aprendizaje dinámico y contextualmente relevante, pero es fundamental que se comprendan los matices. 

Si queremos tener una oportunidad de luchar contra los actores de las amenazas -y siempre tienen una ventaja sobre una organización- los desarrolladores necesitan un entorno de formación integral, con un aprendizaje en capas que construya continuamente habilidades impregnadas de las mejores prácticas.

Las medidas de seguridad defensivas impulsadas por los desarrolladores no son una victoria automática.

Nuestra filosofía gira en torno al desarrollador como elemento central de una estrategia de seguridad preventiva, desde el nivel de código hacia arriba. Esto es un hecho, y los desarrolladores capacitados en seguridad proporcionan el camino más fácil para frustrar los tipos de errores de seguridad comunes que son evidentes en los patrones de codificación pobres (como Log4Shell, como un ejemplo reciente y devastador).

Sin embargo, las técnicas defensivas que podemos emplear para capacitar a los desarrolladores varían, aunque puedan existir con razón en el mismo cubo de formación. 

Por ejemplo, imagina que te dijeran cómo hornear una tarta, utilizando únicamente indicaciones basadas en lo que no hay que hacer. "No lo hornees demasiado", y "no te olvides de los huevos" deja abierta la interpretación, y un enorme potencial de errores que tendrán un resultado final apto para ¡Lo he clavado!. Lo mismo ocurre con la educación en seguridad defensiva; lo que no hay que hacer es una parte muy limitada de la conversación, y no ofrece ningún consejo práctico para actuar realmente con una mentalidad defensiva. Se puede decir a los desarrolladores "no configuren mal esa API", pero si no se entiende lo que constituye una configuración correcta y segura, hay mucho margen de error.

Los desarrolladores no tendrán un impacto positivo en la reducción de la vulnerabilidad sin una comprensión fundamental de cómo funcionan las vulnerabilidades, por qué son peligrosas, qué patrones las causan y qué patrones de diseño o codificación las solucionan en un contexto que tiene sentido en su mundo. Un enfoque de andamiaje permite que las capas de conocimiento ofrezcan una imagen completa de lo que significa codificar de forma segura, defender una base de código y ser un desarrollador consciente de la seguridad. Y sí, parte de ese aprendizaje por capas debe dedicarse a la ofensiva, y a entender la mentalidad de un atacante; esto es fundamental para perfeccionar las habilidades de pensamiento lateral, que son inestimables en el modelado de amenazas y la estrategia defensiva. 

Reforzar los malos patrones de codificación es una trampa que no podemos ignorar.

Una desafortunada realidad con algunos métodos de aprendizaje para desarrolladores es que la parte "defensiva" -incluso cuando la formación está estructurada con técnicas ofensivas- puede reforzar los malos hábitos, incluso si técnicamente están validando la seguridad del código. 

La producción de código de alta calidad debería ser la línea de base en todo el desarrollo de software, pero la definición de "calidad" todavía parece ser objeto de debate. La realidad es que el código inseguro no puede considerarse de calidad, aunque sea funcional y bonito. Lo mejor es que el código seguro tampoco es inherentemente de alta calidad. En otras palabras, unos patrones de codificación deficientes pueden solucionar un problema de seguridad, pero al hacerlo, introducir otro, o potencialmente romper el software por completo. 

Veamos un ejemplo de código de baja calidad en forma de corrección de la autenticación rota, así como la versión más segura para las mejores prácticas:

utilizando System;
usando System.Collections.Generic;
usando System.Linq;
usando System.Threading.Tasks;
usando Microsoft.AspNetCore.Authorization;
usando Microsoft.AspNetCore.Http;
usando Microsoft.AspNetCore.Mvc;
namespace BadFixesAPI.Controllers
{
    [Ruta("api/[controlador]")]
    [ApiController]
    public class AlertsController : ControllerBase
    {
        private DatabaseContext context = new DatabaseContext();
        [HttpGet(Name = "GetAlerts")]
        // Does not ensure that the user is authenticated 
        public IEnumerable<Alert> Get()
        {
            return context.GetAlerts();
        }
        [HttpGet(Name = "GetAlerts")]
        // Ensures that the user is authenticated, but does not check any roles
        [Authorize()]
        public IEnumerable<Alert> GetBadFix()
        {
            return context.GetAlerts();
        }
        [HttpGet(Name = "GetAlerts")]
        // Ensures that the user is authenticated, AND that they have the "Administrator" role
        [Authorize(Roles = "Administrador")]
        public IEnumerable<Alert> GetGoodFix()
        {
            return context.GetAlerts();
        }
    }
}

En el primer fragmento, no hay ninguna comprobación para verificar que el usuario está autenticado, lo cual es lo más inseguro que puede haber. El segundo, aunque es mejor en cuanto a que realiza una comprobación de autenticación, no investiga los roles asignados ni si los permisos son lo suficientemente altos para la información solicitada. El tercero comprueba tanto la autentificación del usuario como que tenga asignado el rol de "Administrador". En una época en la que el control de acceso con mínimos privilegios debería ser la norma en la mayoría de los casos, es fundamental que se establezcan y comprueben los roles para garantizar que sólo se pueda acceder a la información cuando sea necesario. 

La máxima prioridad de los desarrolladores es crear funcionalidades, y aunque la seguridad no se deja de lado intencionadamente, no tienen necesariamente las habilidades necesarias para evitar los malos patrones de codificación que conducen a errores de seguridad, y el punto de referencia de un buen ingeniero rara vez incluye la destreza en la codificación segura. Fomentamos indirectamente esos malos hábitos si las características son lo suficientemente impresionantes, y es esta mentalidad la que tiene que cambiar. El problema es que la forma en que algunas vías de aprendizaje fomentan la corrección práctica del código también refuerza potencialmente el código que es seguro, pero de calidad inferior. Al aplicar un binario "sí esto es seguro / no esto no es seguro" assessment, en lugar de profundizar en si es realmente el mejor enfoque para resolver el error y mantener la integridad del software, hay demonios en los detalles que pasan desapercibidos. 

Sin llevar a los desarrolladores a través de todo el proceso para obtener una visión completa de la codificación segura, este enfoque perpetúa los mismos problemas que intenta resolver. Imagínese que todos obtuviéramos nuestro carné de conducir basándonos únicamente en nuestra capacidad para conducir un vehículo hasta un destino; un aprobado aunque nos hayamos saltado semáforos en rojo, hayamos atravesado un seto y nos hayamos saltado por poco a un peatón que cruzaba la calle para llegar allí. Completamos la meta, pero lo que más importa es el trayecto que hicimos para llegar a ella. 

Hay que capacitar a los desarrolladores para que se preocupen más por crear software seguro.

El desarrollador moderno tiene que mantener un montón de platos girando, y no es de extrañar que encuentren la formación en seguridad aburrida, especialmente cuando no se implementa teniendo en cuenta su día de trabajo, y les aleja de sus plazos y prioridades. También es completamente injusto cambiar sus KPI para incluir un énfasis en la codificación segura, cuando no tienen las habilidades construidas a partir de oportunidades de aprendizaje regulares y adecuadas y herramientas complementarias. Sin embargo, no se puede exagerar la importancia del desarrollo de software seguro, y conseguir que los desarrolladores se pongan de acuerdo es crucial. 

Como antiguo desarrollador, por lo general, queremos hacer un gran trabajo, y ser visto como un corte por encima de los demás en términos de producción de calidad es muy motivador. Incentivar a los desarrolladores para que se comprometan con el desarrollo continuo de habilidades de seguridad es una obviedad, y deben ser recompensados por reconocer la importancia de la seguridad a nivel de código. Los programas de campeones de seguridad, las recompensas por errores y los hackathons pueden ser grandes oportunidades para construir una cultura de seguridad positiva, y aquellos que se arremangan y participan deben obtener el botín.

Nos gustaría contar con su permiso para enviarle información sobre nuestros productos y/o temas relacionados con la codificación segura. Siempre trataremos sus datos personales con el máximo cuidado y nunca los venderemos a otras empresas con fines de marketing.

Enviar
Para enviar el formulario, habilite las cookies "Analytics". Siéntase libre de desactivarlas de nuevo una vez que haya terminado.