Insecure Direct Object Reference

← Volver al inicio

Siendo parte de la categoría #1 del OWASP Top 10, IDOR es una vulnerabilidad que expone información de que no deberia ser accesible a ciertos usuarios basado en sus permisos.

Se tiene que dejar en claro que no estamos hablando de niveles de acceso, esta vulnerabilidad puede estar presente aun y cuando el usuario que esta accediendo a la información tenga privilegios elevados.

Por ejemplo, un usuario administrador, no deberia poder ver los records de otro administrador por el mero hecho de tener ese rol.

Lo que sucede en este fallo de seguridad, es que un usuario, gracias a un fallo de diseño en la aplicacion, logra obtener información de la cual no es propietario.

Podemos verlo de la siguiente manera. Imaginemos que tenemos un endpoint como el siguiente.

http://example.com/api/groups/{group_id}/members

La aplicacion puede obtener los miembros de un grupo buscando mediante el Id del grupo.

http://example.com/api/groups/12/members

[
   {"id": 101, "name": "Alice"},
   {"id": 102, "name": "Bob"}
]

La falla se presenta en el momento en que alguien puede tomar la URL y simplemente cambiando el ID, obtener los miembros de cualquier otro grupo.

http://example.com/api/groups/13/members

[
   {"id": 201, "name": "Charlie"},
   {"id": 202, "name": "Diana"}
]

Con un script simple para iterar los IDs (/13, /14, /15…), un atacante podría extraer todos los registros de la base de datos.

Fix

Para evitar esta vulnerabilidad debemos de aplicar reglas de control de acceso. (De nuevo, puede que ya tengamos una forma de proteger los endpoints para que solo sean accesibles para usuarios elevados (administradores del grupo,etc) pero que un usuario tenga el rol de administrador no le deberia permitir ver la información del resto de grupos).

OWASP y otras fuentes lo describen como ownership. Debemos asegurarnos de que el usuario que esta solicitando la información, sea dueño de dicha información.

En este ejemplo la forma en que aplicamos esta validacion seria de la siguiente manera.

app.MapGet("api/groups/{groupId}/members", async (int groupId, ClaimsPrincipal user) =>
{
    var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);

    // 1. Verificar si el usuario pertenece al grupo
    var isMember = await groups.IsMemberAsync(groupId, userId);

    if (!isMember)
    {
        // 2. Retornar 404 en lugar de 403 para evitar enumeración de recursos
        return Results.NotFound();
    }

    // 3. Obtener y retornar los miembros
    var members = await groups.GetMembersAsync(groupId);
    return Results.Ok(members);
});

Podríamos regresar un código como 403 que diga que no tenemos permiso para acceder a dicho recurso, pero esto daría pie a otra vulnerabilidad en la que un usuario podria realizar peticiones a nuestro endpoint para revelar qué IDs existen dentro de nuestra base de datos

Esto tiene una desventaja y es que si el desarrollador olvida agregar la validacion de control de acceso, la vulnerabilidad seguira presente, para evitar esto podemos hacer uso de RLS (Row Level Security) a nivel de la base de datos.

← Volver al inicio