Pruebas de seguridad en aplicaciones web
¿Alguna vez has tenido curiosidad sobre las pruebas de seguridad, pero no sabes por dónde empezar? En este artículo te traigo una guía para que puedas empezar a hacer pruebas de seguridad en tus aplicaciones web, basándonos en algunas de las vulnerabilidades más comunes mostradas en el Top 10 de OWASP, una organización sin fines de lucro que se dedica a mejorar la ciberseguridad.
La página usada para estas pruebas es OWASP Juice Shop, una aplicación web vulnerable que nos permite practicar y aprender sobre seguridad en aplicaciones web.
Autenticación y autorización
A01:2021-Broken Access Control se refiere a cuando un usuario puede ingresar a recursos que no debería. Como permitir que un usuario no autenticado pueda ver una página que solo debería ser accesible por usuarios autenticados o cualquier usuario pueda consultar a la información de otro usuario.
En este ejemplo veremos como con el usuario [email protected]
podemos obtener información del usuario admin. Esto es provocado porque nuestro sistema no está validando correctamente que la información solicitada pertenece al usuario que está haciendo la petición.
Para hacer esto primero tendríamos que tener sesión iniciada con el usuario Bender. Al ir al carrito, y viendo la pestaña de Network en las herramientas de desarrollador, podemos ver que la petición que se hace para obtener la información del carrito y los headers que se envían en la petición. Aquí podemos ver que nuestro JWT se envía en el header Authorization
.
Si vamos directamente a la URL que estamos viendo no funciona debido a que falta el header de Authorization
.
Pero si usamos un cliente como Postman y enviamos el header Authorization
con el JWT que obtuvimos en la petición anterior, podemos ver que nos responde con la misma información y ahí podemos ver que ese carrito pertenece al UserId
número 3.
Ahora, cambiamos el ID del carrito que se está consultando por el número y hacemos de nuevo la petición nos responderá con la información del carrito del UserId
número 1 que es el admin.
A07:2021-Identification and Authentication Failures se refiere a cuando nuestro sistema de autenticación no es seguro. Ya sea por permitir contraseñas débiles, por no tener un sistema de bloqueo de cuentas por intentos fallidos, por no tener un sistema de recuperación de contraseñas seguro, etc.
Por ejemplo, aquí podemos iniciar sesión usando las credenciales de email [email protected]
y password admin123
, reflejando que no tenemos un control adecuado para validar la fortaleza de las contraseñas.
Inyección de código malicioso
A03:2021-Injection se refiere a cuando nuestro sistema no sanitiza la información que recibe y permite que se inyecte código malicioso en nuestra aplicación. Por ejemplo, en un sistema de búsqueda no limpiamos o validamos los términos de búsqueda, podríamos permitir que se inyecte código malicioso o si nuestras consultas a la base de datos no son parametrizadas alguien puede ejecutar consultas SQL para obtener información sensible.
Para la inyección de código malicioso vamos a ver dos de los ataques más comunes: SQL Injection y XSS (Cross Site Scripting).
SQL Injection
Cuando hacemos consultas a la base de datos y no están parametrizadas o no usamos un URM (Object Relational Mapping) podemos permitir que se inyecte código malicioso. Por ejemplo, si tenemos un formulario de login y no parametrizamos la consulta alguien puede autenticarse sin necesidad de tener las credenciales correctas.
En este ejemplo lo que hacemos es escribir ' OR 1=1; --
en el campo de email y nos autenticamos como el usuario admin
, no necesitamos saber su contraseña y por eso en el input de password podemos agregar cualquier cosa.
¿Cómo funciona?
La creación dela query que se hace a la base de datos está escrita así en el código de la aplicación:
`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`
Sustituimos los datos que nos llegan en la petición y quedará de la siguiente forma:
SELECT * FROM Users WHERE email = 'user' AND password = 'hashed-password' AND deletedAt IS NULL
Esta misma implementación es la que permite que se pueda hacer SQL Injection, al no hacer una query parametrizada, si nosotros enviamos ' OR 1=1; --
se inyecta en la query y la consulta queda así:
`SELECT * FROM Users WHERE email = '' OR 1=1; -- ${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`
Y lo que recibirá la base de datos será esto:
SELECT * FROM Users WHERE email = '' OR 1=1; -- ' AND password = 'hashed-password' AND deletedAt IS NULL;
De esta forma la query siempre retornará un usuario y no importa que contraseña se envíe, y luego de eso me enviará el token de autenticación del primer usuario que haya encontrado.
XSS (Cross Site Scripting)
Cuando no sanitizamos la información que recibimos y la mostramos en nuestra aplicación podemos permitir la ejecución de scripts no autorizados en nuestro sitio. Por ejemplo, si tenemos un sistema de comentarios o podemos compartir enlaces con términos de búsqueda en nuestro sitio, y no sanitizamos la información que ingresan los usuarios, los atacantes podrían inyectar scripts para que se ejecuten cuando alguien entre a nuestro sitio.
Aquí podemos ver que cuando nosotros ingresamos un término de búsqueda, después dle cliente renderiza todo tal cual nosotros lo escribimos.
Ahora ingresamos <img/src/onerror=prompt(8)>
esto lo que hará es intentar cargar la imagen de la propiedad src
, lo cual fallará y al fallar ejecutará la instrucción que nosotros le colocamos en el fallback onerror
que es prompt(8)
, que lo que hace es mostrar un mensaje en el navegador con el número 8.
Podemos ver que se ejecuta el script correctamente y también podemos encontrar el mismo script en el código fuente de la página.
Exposición de datos sensibles o problemas de cifrado
A02:2021-Cryptographic Failures principalmente hace referencia a errores en la implementación de cifrado y descifrado de información. Por ejemplo, si usamos un algoritmo de cifrado débil o si no ciframos la información que se envía a través de la red. Aquí también podemos encontrar lo que anteriormente se llama Sensitive Data Exposure.
Sensitive Data Exposure
Cuando exponemos información sensible de alguna forma, aunque no se vea directamente en nuestro sitio. Por ejemplo, si tomamos el JWT que nos regresa el servidor y lo decodificamos con alguna herramienta como jwt.io, podríamos encontrar información sensible como contraseñas o la posibilidad e encontrar tokens de acceso a otras partes de nuestro sistema.
También, combinado con el problema de Autenticación y Autorización, podríamos dejar acceso libre a una ruta de nuestro servidor donde algún atacante podría encontrar información útil para atacar nuestro sistema.
Con esto ya puedes comenzar a hacer pruebas de seguridad en tus aplicaciones web
Estas son solo algunas de las vulnerabilidades que podemos encontrar en nuestras aplicaciones web, pero son las más comunes y las que más se explotan. Si quieres aprender más sobre seguridad en aplicaciones web te recomiendo que visites la página de OWASP y que leas el Top 10 de OWASP.
Además, para ejecutar estas pruebas no es necesario que seas un experto o una experta en ciberseguridad o en desarrollo web, solo necesitas tener curiosidad y ganas de aprender 🚀.