
Repasa y practica la codificación segura
Nunca cesa de ser evidente lo inseguro
que tiende a ser el software utilizado por personas
y organizaciones en casi todas las industrias mundiales.
Basta con echar un vistazo a las noticias de The Record
del último mes para encontrar ciberataques dirigidos
a los sectores de aviación,
espacio
y educación
(como vimos recientemente,
este último es uno de los más atractivos
para los actores de amenazas actualmente).
Si bien es cierto que muchos ataques suelen tener éxito gracias
a la ingeniería social
(p. ej., campañas de phishing),
muchos otros logran su objetivo a través
de otro importante vector de ataque:
la explotación de vulnerabilidades de seguridad en el software.
Aquí no estamos hablando
algo que afecte únicamente a los débiles y pequeños.
Las grandes empresas que proporcionan software
como producto o servicio
(ejemplos recientes: Google,
Siemens,
y Microsoft),
así como organizaciones bien conocidas que hacen uso de software
(ejemplos recientes: una agencia federal,
Aurubis,
y Mitel),
siguen viéndose gravemente afectadas por los ciberataques.
Muchas vulnerabilidades explotadas por hackers maliciosos
para robar información o interrumpir operaciones se encuentran
en el código fuente de las aplicaciones
(es decir, aquellas instrucciones que definen su estructura
y funcionalidad y que son interpretadas por los dispositivos).
Por eso, una de las mejores formas de prevenir los ciberataques
y sus repercusiones es desarrollar correctamente los productos de software,
escribiendo un código fuente seguro desde el principio
del ciclo de vida de desarrollo de software (SDLC).
¿Qué es la codificación segura?
La codificación segura o programación segura
es la práctica de desarrollo de software en la que se evita
la aparición de errores de programación
que den lugar a vulnerabilidades de seguridad.
Esta actividad implica un alto conocimiento de lenguaje
de programación en uso y el seguimiento juicioso
de convenciones y principios o estándares de codificación segura.
Es por ello que los equipos de desarrollo de cualquier empresa interesada
en su ciberseguridad deben estar capacitados al respecto.
Resulta problemático que muchos desarrolladores
vean como un obstáculo la inclusión de principios
de seguridad en el desarrollo de software.
Una de sus causas es la continua demanda de rápida salida
de los productos y de nuevas funcionalidades en ellos.
En su prisa
por responder rápidamente a las peticiones de clientes o usuarios,
a veces dirigidos por directivos apáticos a una cultura de ciberseguridad,
los desarrolladores pasan por alto
la exposición al riesgo.
En otros casos, puede que se les pida
o se les obligue prestar atención a la seguridad,
pero factores simples como falta de concentración
o desconocimiento también pueden impedir una codificación segura.
La falta de conocimientos sobre ciberseguridad
de los desarrolladores de software
es algo habitual hoy en día,
hasta el punto de que pueden ignorar, por ejemplo,
la existencia de estándares públicos como OWASP.
En realidad,
un primer paso para prevenir las vulnerabilidades de seguridad
puede ser disponer de bases de datos de vulnerabilidades estandarizadas
como CWE,
CERT,
CVE,
OWASP
y PA-DSS,
entre otras, y bajo revisión.
(Consulta también nuestro listado
de tipos de vulnerabilidades.)
Las organizaciones que desarrollan
y ofrecen software como producto o servicio,
y aún no lo han hecho, deben empezar a crear
o reforzar la cultura basada en la seguridad dentro de sus unidades.
Aquí es donde entra en juego el famoso enfoque DevSecOps
según el cual la seguridad debe ser responsabilidad
de todos los miembros del equipo
y no solo algo para un equipo de seguridad.
Aunque puede ser un cambio complejo y lento,
es un esfuerzo que vale la pena en términos de costos
y posibilidades de éxito, y en el que pueden intervenir los llamados
Campeones de seguridad (de los
que ya hemos hablado.)
Como veremos más adelante,
el trabajo de los desarrolladores puede verse considerablemente
facilitado por las pruebas de seguridad.
Sin embargo,
sigue siendo esencial que entiendan lo que están haciendo
en términos de riesgos y amenazas,
que sepan dónde están cometiendo errores
y que empiecen a mantener prácticas que
les permitan evitar estas fallas y, por consiguiente,
la aparición de vulnerabilidades en sus productos.
Algunas prácticas de codificación segura
Es fácil encontrar en internet buenas prácticas
o pautas de codificación segura
(p. ej., OWASP DevGuide,
Microsoft Writing Secure Code,
Red Hat Secure Coding Tutorials).
Para este artículo, hemos tomado en parte
como base Secure Coding Practices – Quick Reference Guide
(te recomendamos que la consultes para más detalles)
y hemos añadido otras consideraciones
y algunos consejos valiosos que vale la pena mencionar.
(Consulta también nuestra serie
de requisitos de seguridad.)
Seguridad desde la primera línea de código
Es imprescindible partir de la idea
de no dejar la seguridad para el final del SDLC.
Pensar y actuar a favor de un producto de software seguro
desde la primera línea de código permite evitar elevados costos posteriores.
No solo los costos en la remediación de vulnerabilidades
(estos son mucho menores en las fases
de desarrollo que en las finales o en producción)
sino también los derivados de su explotación,
es decir, las brechas de seguridad.
Los desarrolladores no deben tener como único objetivo
la rápida puesta en producción de un producto con una funcionalidad óptima.
Entre sus principales propósitos,
deberían incluir la salida a producción de un software
de alta calidad que garantice la seguridad.
Pensar como actores de amenazas
Los desarrolladores deberían intentar ver sus creaciones
como si ellos mismos fueran hackers maliciosos.
(Ya escribimos una vez un artículo titulado
¡Piensa como hacker!
que puede servir como referencia acá).
No solo deben centrarse en los fines y casos de uso del producto,
sino también en cómo podrían explotarlo los delincuentes
en caso de tener vulnerabilidades.
Los desarrolladores deben tener claro qué activos
y operaciones serían atractivos para los actores de amenazas.
Deben ser conscientes de las amenazas potenciales
y de los niveles de riesgo y tener en cuenta
y poner en práctica medidas preventivas.
Validación de entradas
El simple uso de la aplicación o el software desarrollado,
concretamente la introducción de datos, suele representar un riesgo.
Por ejemplo, los ataques conocidos como inyección SQL
y cross-site scripting (XSS)
pueden producirse debido a vulnerabilidades derivadas
de confiar en fuentes de datos externas y en el input del usuario,
por lo que el software no distingue entre comandos y datos.
En otras palabras,
ciertos caracteres pueden entrar en la aplicación funcionando
como código malicioso y hacer que se comporte de forma anormal
o desviándose de su funcionamiento previsto.
De ahí la necesidad de validar continuamente
lo que entra en el producto informático.
Los desarrolladores deben asegurarse que las fuentes de datos
se clasifican como fiables y no fiables.
Su producto debe validar adecuadamente el input (principalmente)
procedente de fuentes no fiables.
Debe verificar las propiedades de los datos entrantes
y aceptar solo los inputs que cumplan unas características específicas
(por ejemplo, tipo, rango, longitud, caracteres permitidos).
Si los inputs no las cumplen, la aplicación debe rechazarlos.
A este proceso, los desarrolladores deben añadir la
codificación de salida,
o output, en la que todo input que no sea de confianza
se transforme a una forma segura,
permanezca como dato y no se ejecute como código.
Autenticación y gestión de contraseñas
El software debe verificar mediante
un proceso estandarizado la identidad del usuario
o entidad que interactúa con este,
especialmente cuando se intenta acceder a recursos
que no están destinados a ser públicos
o a sistemas externos con material confidencial.
Las fallas de autenticación deben generar respuestas
que no especifiquen cuáles de los datos solicitados
eran erróneos o inválidos.
Las operaciones críticas, como las transferencias de dinero,
por ejemplo,
deben solicitar una nueva autenticación o una autenticación multifactor.
Si la aplicación almacena credenciales,
los desarrolladores deben asegurarse de que siempre
sean hashes sólidos de contraseñas
criptográficamente unidireccionales.
Para reforzar la complejidad de las contraseñas
(preferiblemente frases de contraseña),
la aplicación debe exigir a los usuarios
que incluyan en ellas números y caracteres especiales,
además de minúsculas y mayúsculas.
Tras varios intentos fallidos de inicio de sesión por parte de un usuario,
el software debería desactivar esa cuenta durante un periodo determinado.
Además, la modificación de la contraseña debe controlarse adecuadamente,
y la aplicación debería notificar al usuario cada vez que ocurra.
Control de acceso y gestión de sesiones
Además de la verificación de la identidad del usuario,
el producto debe contar con un proceso que permita
o deniegue el acceso a los recursos.
Los desarrolladores deben restringir el acceso a determinados recursos
(incluidas URL protegidas, funciones, servicios, archivos y datos críticos)
solo a unos pocos usuarios autorizados.
Siempre deben aplicar el principio de mínimo privilegio.
Por defecto, el acceso debe ser denegado,
y el sistema debe mantener y verificar las condiciones o características
(más allá de la verificación de roles) para permitirlo.
Lo ideal es que el programa restrinja
a los usuarios el acceso únicamente a los recursos necesarios
para realizar sus tareas o trabajos.
En un periodo determinado,
debe limitarse el número de transacciones de un usuario
o entidad y deben eliminarse las cuentas no utilizadas.
Además, los desarrolladores deben establecer tiempos de inactividad
de sesión lo más cortos posible,
no permitir inicios de sesión simultáneos con la misma cuenta
y generar nuevos identificadores de sesión
para sustituir periódicamente a los usados.
Criptografía y protección de datos
La protección o confidencialidad de los datos depende
en gran medida del uso de algoritmos de cifrado conocidos,
bien probados y actualizados para los datos sensibles en tránsito y en reposo.
En línea con lo mencionado anteriormente para las contraseñas,
estas y ninguna otra información sensible debe almacenarse en texto claro
o de cualquier otra forma
que no implique criptografía.
En el código que pueda ser accesible a los usuarios
(no se debe permitir que los usuarios descarguen
el código fuente del servidor),
los desarrolladores deben eliminar los comentarios
que revelen información confidencial.
Lo mismo debe hacerse con la documentación innecesaria sobre la aplicación.
El producto de software también debe permitir eliminar
los datos confidenciales cuando ya no sean útiles.
Este mismo tipo de información no debe estar presente en las cookies,
y el manejo de tales datos no debe conducir
a la generación de copias en caché.
Gestión de errores y registro
En relación con lo que hemos mencionado
para los errores de autenticación,
las actividades no válidas en la aplicación
o el producto pueden generar mensajes de error.
La idea es que estos mensajes no revelen información
que pueda ser útil para posibles atacantes
(p. ej. identificadores de sesión,
detalles del sistema o información de la cuenta).
Esta misma información no debe almacenarse en los registros.
El registro de los eventos que se producen
en el código permite identificar errores.
Las acciones que provocan fallas en la aplicación
(p. ej. validación de input, autenticación, control de acceso,
funciones administrativas, módulos criptográficos)
deben ser registradas y bloqueadas.
Los desarrolladores deberían restringir el acceso de todos
los registros y solo dar acceso a un grupo de usuarios autorizados.
Configuración y control de sistema
Los desarrolladores deben asegurarse de que los servidores,
marcos de trabajo y otros componentes del sistema estén
en sus últimas versiones verificadas
con todos los parches de seguridad pertinentes aplicados.
Además, deben eliminarse todos los archivos
y componentes de aplicación innecesarios
(p. ej., de código de terceros).
Esto guarda cierta relación con la idea de mantener el código
y los sistemas lo más limpios y sencillos posible.
Al reducir la complejidad del producto,
incluyendo solo lo realmente necesario,
los desarrolladores reducen la probabilidad
de que surjan vulnerabilidades de seguridad.
Además, se recomienda que sigan utilizando sistemas de control
de código fuente y un seguimiento minucioso de los cambios.
Revisión de código fuente
Las anteriores son solo algunas de las prácticas recomendadas
para una codificación segura.
Existe para ellas un complemento casi indispensable
que permite a los desarrolladores garantizar
la alta calidad de sus productos de software.
Se trata de las pruebas de seguridad,
especialmente en modo de revisión de código fuente.
En una entrada reciente del blog,
describimos este tipo de prueba y los beneficios
que puede aportar a una organización que desarrolla software.
Básicamente, se trata de una contribución de un proveedor externo,
como Fluid Attacks, en la que herramientas automatizadas y humanos
(algunos proveedores se limitan erróneamente al uso de herramientas)
tienen la misión de detectar vulnerabilidades
de seguridad en el código fuente.
Aunque los grupos de desarrolladores
pueden educarse o recibir formación sobre prácticas
como las descritas anteriormente,
no es extraño que sigan apareciendo fallas
y vulnerabilidades en su trabajo con el paso del tiempo.
A través de
la revisión de código fuente de Fluid Attacks,
en la que participan nuestras herramientas
y nuestro equipo de hackers éticos con técnicas
como SAST
y SCA,
y en la que damos soporte a unos 40 lenguajes de programación
y utilizamos más de 60 estándares internacionales de seguridad
como base para la evaluación,
informamos a tus equipos de desarrollo de los problemas de seguridad
que surgen en sus construcciones.
Como ya hemos dicho,
estos informes les sirven de retroalimentación,
y la práctica de remediar las vulnerabilidades identificadas alimenta
sus conocimientos sobre codificación segura.
Aunque no dejarán de producirse errores,
podrán advertirlos y solucionarlos más fácilmente.
Como el software tiende a evolucionar
a un ritmo increíble para satisfacer las necesidades de los usuarios,
ofrecemos la revisión segura de código como parte
de nuestro servicio de Hacking Continuo.
En este proceso constante,
estamos atentos a todos los cambios en tus repositorios,
y añadimos técnicas más allá de la revisión segura de código,
como las pruebas de seguridad de aplicaciones dinámicas
(DAST).
Contáctanos
si quieres descubrir qué están pasando por alto tus equipos de desarrollo
y qué está poniendo en riesgo a tu organización.
Regístrate aquí
si quieres empezar con una prueba gratuita de 21 días de pruebas
de seguridad continuas mediante nuestras herramientas automatizadas.
*** This is a Security Bloggers Network syndicated blog from Fluid Attacks RSS Feed authored by Felipe Ruiz. Read the original post at: https://fluidattacks.com/es/blog/practicas-codificacion-segura/