AUDITORÍA DE SEGURIDAD A NIVEL DE CÓDIGO (I)

Autor: Alejandro Rueda Romero

En el presente artículo se explicará la importancia de las revisiones de código en el DevSecOps, para poder detectar de forma temprana las vulnerabilidades durante el desarrollo. En el pasado la única auditoría de seguridad que se realizaba eran las pruebas de penetración, pero solo centrarse en los test de penetración supone un mayor coste para arreglar las vulnerabilidades, y no llegar a encontrar todas las vulnerabilidades posibles. 

Las revisiones de código es lo que se podría llamar análisis estáticos, mientras que las pruebas de penetración serían más los análisis dinámicos. Los análisis estáticos detectan más fácilmente un tipo de vulnerabilidades que los dinámicos, y a la inversa, por ello es importante realizar siempre ambas pruebas. La revisión de código es una de las claves fundamentales para prevenir problemas de seguridad en el software durante el desarrollo, principalmente es una auditoría orientada para la fase de pre-producción. Se pondrán algunos ejemplos de vulnerabilidades que nos podemos encontrar en el código.

¿Qué es una revisión de código seguro?

Una revisión de código segura es parte del proceso de revisión de código para identificar las mejores prácticas que faltan al principio del ciclo de vida de desarrollo de software (SDLC), lo que resulta en menos vulnerabilidades en la producción. Con el tiempo, los ingenieros de software han definido varias prácticas recomendadas de seguridad que pueden proteger una aplicación contra vulnerabilidades web comunes, como las enumeradas en OWASP Top 10 o CWE / SANS Top 25:

Supongamos que te toca realizar una revisión de código. ¿Qué deberías buscar?

  • Autenticación remota / Control de acceso roto
  • Seguridad de la comunicación de la base de datos
  • Cifrado de datos
  • Protección de Datos
  • Manejo de errores
  • Gestión de archivos
  • Credenciales codificadas
  • Validación de entrada
  • Problemas específicos del idioma (por ejemplo, malabarismo de tipos en PHP)
  • Gestión de la memoria
  • Sanitización de la salida

Esa es una gran lista. Por supuesto, no podrá abordar todos estos sin pasar semanas o más, y por lo general se dispone de tiempo limitado para realizar dichas auditorías. Por lo tanto, debemos reducir la lista y centrarnos solo en las vulnerabilidades más importantes y en las que es mejor detectar mediante revisiones de código seguro. Tenga en cuenta que esta etapa no está destinada a encontrar necesariamente todas las fallas de seguridad en una aplicación, sino a ofrecer a los desarrolladores información sobre las clases de vulnerabilidades que existen. Afortunadamente, algunas de las mejores prácticas de seguridad mencionadas anteriormente son más importantes y efectivas que otras. Por lo tanto, podemos reducir esa lista a cinco elementos en función de la gravedad y la cantidad de fallas que evita cada práctica recomendada:

  • Autenticación rota / Control de acceso roto
  • Seguridad de la comunicación de la base de datos
  • Cifrado de datos
  • Validación de entrada
  • Sanitización de salida

Validación de entrada

La validación de entrada es el mecanismo de defensa más fundamental y se puede utilizar para prevenir muchas vulnerabilidades web, incluidas inyecciones, secuencias de comandos entre sitios, falsificación de solicitudes del lado del servidor, inclusión de archivos locales y otras. Esta mejor práctica tiene sus raíces en un principio simple: nunca confíe en la entrada del usuario. Por ejemplo, si su aplicación web le pregunta al usuario su edad, solo debe permitir números para esa variable. ¿Está pidiendo un número de teléfono, una dirección de correo electrónico o una URL?

 

$phonenum = $_GET[‘phonenum’];

//Format: 000–0000–0000

if(preg_match(“/^[0–9]{3}-[0–9]{4}-[0–9]{4}$/”, $test56)) {

// $test56 is valid

} else {

// $test56 is invalid

}

Autenticación rota / Control de acceso roto

La autenticación rota y el control de acceso roto son dos tipos de vulnerabilidades lógicas que no se pueden identificar fácilmente con herramientas automatizadas, ya que requieren una comprensión del comportamiento de la aplicación.

Se produce una vulnerabilidad de autenticación rota cuando la aplicación no puede verificar si el usuario está conectado antes de permitir el acceso a un recurso / característica específica. A continuación, se muestra un breve ejemplo:

@app.route(‘/internal-dashboard/users’, methods=[‘GET’])

def showUsers():

users = db.getAllUsers()

return render_template(“dashboard/users.html”, users=users)

En este caso, cualquier persona que conozca la ruta puede ver los detalles de todos los usuarios registrados sin iniciar sesión.

Una vulnerabilidad de Control de acceso roto ocurre cuando la aplicación web no puede verificar si el usuario está autorizado para acceder a un recurso específico. Como resultado, un atacante puede ver, modificar o eliminar datos que pertenecen a otros usuarios.

Uso de algoritmos criptográficos débiles con fines criptográficos

Un algoritmo hash criptográfico seguro se define como un algoritmo que genera un hash único de tamaño fijo para cualquier entrada de longitud variable. Una de las condiciones para que una función hash se considere segura es la resistencia a colisiones. Esto significa que el algoritmo debería tener una probabilidad extremadamente baja de producir el mismo hash para dos entradas diferentes.

En los últimos años, los investigadores lograron identificar y demostrar vulnerabilidades en dos de los algoritmos hash más utilizados (SHA1 y MD5). Por lo tanto, al revisar el código, asegúrese de que la aplicación no utilice SHA1, MD5. Por ejemplo, es recomendable utilizar un SHA256.

Además, es importante asegurarse de que los algoritmos criptográficos inseguros no se utilicen también para otros fines (por ejemplo, comunicación, almacenamiento seguro de datos). Por ejemplo, DES ya no se considera un algoritmo seguro, mientras que AES se considera el algoritmo de cifrado simétrico a utilizar.

Credenciales en el código

Los desarrolladores web a veces usan credenciales / secretos codificados para pruebas rápidas y de fácil acceso cuando es necesario. Sin embargo, a veces los desarrolladores olvidan eliminar los secretos antes de implementar la aplicación en producción e incluso publicarlos en plataformas git. Esta práctica presenta un riesgo de seguridad significativo que puede permitir a los atacantes eludir los mecanismos de autenticación o aumentar la gravedad de una vulnerabilidad que ya encontraron. En 2016, Uber tuvo una violación de datos que expuso la información de 57 millones de clientes debido a algunas credenciales codificadas disponibles públicamente en uno de sus repositorios de Github. 

$link = mysqli_connect(“75.77.1.133”, “root”, “password priv”, “prod_db”);

if (!$link) {

echo “Error: Unable to connect to MySQL.” . PHP_EOL;

echo “Debugging errno: “ . mysqli_connect_errno() . PHP_EOL;

echo “Debugging error: “ . mysqli_connect_error() . PHP_EOL;

exit;

}

Alejandro Rueda Romero – Ingeniero en ciberseguridad