El IDOR es un tipo de vulnerabilidad que ocurre cuando una aplicación le permite a un usuario acceder directamente a objetos (como recursos, funciones o archivos) en función de la consulta que éste realice, sin realizar el debido control de acceso.
Es una vulnerabilidad muy común en los sitios web ya que tiene que ver con errores de implementación de control de acceso.
Se ubica en la lista Top 10 de OWASP 2017 (lista de riesgos de seguridad más comunes en aplicaciones web) y pertenece a la clasificación de vulnerabilidades relacionadas con el control de acceso (Broken Access Control).
Por otro lado, está catalogada por la Common Weakness Enumeration (CWE) como CWE-639: Authorization Bypass Through User-Controlled Key y puedes encontrarlas como IDOR y BOLA (Broken Object Level Authorization).
Riesgos de la vulnerabilidad
Es casi imposible definir cuál es el impacto de un IDOR de forma general, ya que depende de la interacción que consiga tener el atacante con el servidor al explotar la vulnerabilidad.
Sin embargo, se puede afirmar que su presencia en un aplicación web puede desencadenar:
- Brechas de información: al acceder a información sensible, esta se puede leer, modificar o borrar, y al mismo tiempo afectar al servidor, usuarios o empresas.
- Modificación de privilegios: al ejecutar funcionalidades reservadas para otros usuarios con diferentes privilegios (como pueden ser roles administrativos u otros roles de su mismo nivel).
Casos comunes de IDOR
1 – Al solicitar información del usuario
Un sitio web utiliza la siguiente URL para acceder a una página con información de un usuario:
https://sitio-inseguro.com/user_info?user_id=998 |
El número de usuario (el valor del parámetro user_id) se utiliza directamente como índice de registro en las consultas que se realizan en la base de datos.
Si no se implementa un control de acceso, un atacante puede simplemente modificar el valor del número de usuario desde la URL y ver la información personal de otros usuarios.
Es decir, en este caso, el IDOR le permite al atacante realizar un movimiento horizontal de privilegios.
2 – Al cambiar la contraseña de un usuario
Una aplicación mobile utiliza el siguiente endpoint de su API para modificar la contraseña de la cuenta del usuario, actualizando la información de una base de datos en el back-end:
POST /api/v1/editar_cuenta/actualizar_contraseña HTTP/1.1 Host: sitio-inseguro.com Cookie: session_token=12j3hf6sa8df57re65t4ff8wee5trgf9reg6597th6trf9 Content-Type: application/json;charset=utf-8 Content-Length: 46 {“user_id”:”222“,”password”:”NuevaContraseña“}
Si no se implementa algún un control de acceso, un atacante puede simplemente modificar el valor del parámetro user_id dentro del cuerpo de la solicitud POST para modificar la contraseña de otro usuario.
También, si el atacante cambiara la contraseña de una cuenta administrativa (o cualquier otra con altos privilegios), podría realizar un movimiento vertical de privilegios.
3 – En archivos estáticos
Supongamos que una empresa de transporte genera certificados de emisión de boletos referidos a sus clientes, los cuales tienen información personal de los mismos.
Sin embargo, los archivos se guardan usando un nombre de archivo incremental, por lo que los clientes acceden a su certificado visitando una URL como la siguiente:
https://sitio-inseguro.com/fake-bus/certificados/177.pdf |
En este escenario, un atacante puede simplemente modificar el nombre del archivo para acceder a certificados de otros usuarios y obtener su información personal.
Cómo se ve la vulnerabilidad IDOR en el código
Ejemplo con código PHP estándar
Si tomamos como ejemplo el Caso 1 – Al solicitar información del usuario.
https://sitio-inseguro.com/user_info?uid=111 |
Tan solo modificando el valor del parámetro id, se podría acceder a la información de otros usuarios, por ejemplo al usuario 112.
Esto sucede debido a que se acepta ciegamente el parámetro suministrado por el usuario para acceder a la información. Así es como se vería la vulnerabilidad en el código:
<?php
$user_id = $_GET[‘uid’];
$user_info = get_user_info($user_id);
[…]
Solución
En el inicio de sesión debes implementar un sistema de cookies y crear las variables de la sesión. En este caso, especificando la siguiente variable:
[…]
$sql = “SELECT * FROM users WHERE email=?;“; //Declaraciones para conectarse a la db
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_bind_param($stmt, “s”, $email);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
[…]
$_SESSION[‘uid’] = $row[‘uid’]; //Se define uid como una variable de sesion
[…]
Luego, se debe cambiar el elemento afectado por la vulnerabilidad, cambiando el origen del parámetro para que no lo tome de una entrada proveniente del usuario, sino que recupere el valor del parámetro de la sesión actual.
<?php
$user_id = $_SESSION[‘uid’];
$user_info = get_user_info($user_id);
[…]
Ejemplo en arquitectura Serverless
En una arquitectura Serverless donde el user ID es tomado desde el cliente, el servidor necesita enviar los valores de los parámetros de una forma segura para mantener su integridad.
Si una API utiliza una arquitectura Serverless, es posible que cargue la información de un usuario utilizando un endpoint similar al siguiente:
/api/v1/profile/user_info/111 |
Si la aplicación no verifica los permisos de la sesión, solo bastaría modificar el valor al final del endpoint para acceder a la información de otro usuario, por ejemplo el 110.
Esto se debe a que el servidor acepta ciegamente la entrada suministrada por el usuario. Esto puede suceder con un código vulnerable como el siguiente.
[…]
router.get(‘/api/v1/profile/user_info/:id’, (req, res) => {
const user_id = req.params.id; //Toma el parametro directamente de la solicitud GET
var db = require(‘../database‘);
db.query(‘SELECT * FROM users WHERE user_id = ?‘, [user_id]) //Se usa ese valor como referencia para ejecutar la consulta SQL
[…]
En este caso, el código permite acceder a información de otros usuarios, según el valor que se le pase utilizando el método GET.
Solución
Una solución viable para este escenario es implementar JSON Web Tokens (JWT).
Los JWT tienen la característica de poder estar firmados digitalmente, con el fin de verificar la integridad de la información contenida en los mismos.
Por ejemplo, si se implementan JWT para administrar las sesiones de esta API, se utilizaría un código similar a este:
let payload = {“id“:111};
let token = jwt.sign( payload,’secret‘, { noTimestamp:true, expiresIn: ‘1h‘ });
Resultando en una cadena de caracteres que conforman el JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTExLCJleHAiOjE2MjE4OTE2NDZ9.Uzv_kQpY649Rvdm96iPWNEaJ457jbIHanVtVF4V6jcM
Ahora bien, debe implementarse en la autenticación de la API y utilizarse como token de sesión. Luego, debe modificarse el elemento con código vulnerable para que utilice el valor suministrado por el JWT. Entonces, el código quedaría similar a lo siguiente:
[…]
router.get(‘/api/v1/profile/user_info’, (req, res) => {
const decoded = jwt.verify(token, ‘secret’);
var user_id = decoded.id
var db = require(‘../database‘);
db.query(‘SELECT * FROM users WHERE user_id = ?‘, [user_id]) //Se usa ese valor como referencia para ejecutar la consulta SQL
[…]
¿Cómo prevenirlo?
Debido a su naturaleza, los IDOR deben tenerse en cuenta desde las etapas de diseño e implementación de la aplicación. Si se implementa un mecanismo de control de acceso robusto, utilizando una metodología adaptada según sea el caso, es posible prevenirlos por completo.
Algunas buenas prácticas para mitigar vulnerabilidades IDOR:
- Evitar mostrar referencias a objetos privados como claves o nombres de archivos.
- Verificar que el acceso a los recursos mediante IDs, tenga un paso de verificación adicional para asegurar que el usuario tenga la autorización adecuada.
- Asegúrate de que las consultas estén dirigidas al propietario del recurso, esto puede lograrse con la correcta implementación de mecanismos de control de acceso.
- Analiza todos los objetos referenciados.
Un pentest nunca está de más
Si bien la vulnerabilidad es relativamente simple, es muy común encontrarla en casi cualquier sitio. Esto se debe, en gran medida, a que los IDORs son difíciles de detectar para las herramientas de análisis de código estático o los escáneres de vulnerabilidades genéricas.
Por esta razón, es recomendable realizar pentest o pruebas de intrusión de forma periódica, para detectarlos mediante la combinación de revisiones manuales y el uso de software especializado.
Aprende más sobre esta vulnerabilidad en el articulo: Cómo detectar la vulnerabilidad IDOR en aplicaciones móviles.
Conclusión
La vulnerabilidad IDOR es muy común debido a errores en la implementación de controles de acceso y también debido a la falta de software capacitado para identificarlo.
Por otro lado, y a pesar de su simpleza, puede tener un impacto grave en tu empresa, causando brechas de información o comprometiendo la integridad de los datos almacenados.
Sigue las buenas prácticas detalladas arriba para que tu código sea seguro y, por otro lado, considera realizar pruebas de intrusión de forma periódica para encontrar cualquier otro tipo de vulnerabilidad y determinar su posible impacto en el negocio.