1. Descripción técnica
Insecure Direct Object Reference (IDOR) es una vulnerabilidad de autorización que ocurre cuando una aplicación expone una referencia a un objeto interno, como un archivo, un registro o una cuenta, y no comprueba si el usuario puede operar sobre ese objeto concreto.
Esta vulnerabilidad permite a un atacante acceder, visualizar, modificar o eliminar datos sensibles simplemente manipulando valores en la URL, parámetros POST o cabeceras, como user_id=123 o invoice_id=999.
Un ataque IDOR exitoso puede comprometer:
- Datos personales (emails, teléfonos, direcciones).
- Información financiera (facturas, transacciones).
- Credenciales almacenadas (a través de respuestas expuestas).
- Funcionalidades administrativas restringidas.
IDOR pertenece a la categoría Broken Access Control. El identificador manipulable facilita localizar el objeto, pero la vulnerabilidad real es la ausencia de una decisión de autorización en el servidor.
IDOR forma parte del grupo de vulnerabilidades asociadas a una mala implementación de controles de acceso, junto con Broken Access Control.
2. Impacto
Una IDOR puede afectar la confidencialidad cuando permite leer objetos ajenos, la integridad cuando permite modificarlos o eliminarlos y, en operaciones privilegiadas, el control de cuentas o funciones administrativas. El alcance depende de las acciones disponibles para la referencia manipulada y de los datos asociados al objeto.
3. Mecanismo y condiciones necesarias
Un flujo representativo es el siguiente:
El usuario autenticado (ej. Alice) accede a su recurso:
GET /api/v1/users/1001/profile→ devuelve sus datos.El atacante (Bob, con
user_id=1002) intenta acceder a:GET /api/v1/users/1001/profilemodificando manualmente el ID.Si el servidor no verifica que Bob tenga permiso para ver el perfil de Alice, devuelve la información de Alice.
La misma comprobación se repite sobre otros identificadores para determinar el alcance, sin asumir que todos los objetos o acciones tienen idénticos controles.
Condiciones comunes que permiten IDOR:
- Referencias controlables por el cliente, sean secuenciales, UUID o nombres de archivo.
- Falta de una comprobación de autorización sobre el objeto y la acción solicitada.
- Confianza en el frontend para ocultar funcionalidades (no es suficiente; el backend debe revalidar).
- APIs que devuelven más datos de los necesarios (
/user/123devuelve email, password_hash, token, etc.).
Tipos comunes de IDOR:
- User-Based IDOR: Un usuario accede a perfiles/órdenes de otros.
- Admin IDOR: Acceso no autorizado a funcionalidades administrativas (
/admin/delete?user_id=1001). - File/Resource IDOR: Acceso a documentos privados (
/download?file_id=55). - Horizontal Privilege Escalation: acceder a objetos de otro usuario del mismo nivel.
- Vertical Privilege Escalation: ejecutar una operación reservada para un rol superior.
4. Validación y detección
Burp Suite (Pro / Community)
- Intercepta y modifica requests fácilmente.
- Repeater: cambia
user_idy observa respuestas. - Intruder: automatiza el fuzzing de IDs (1, 2, 3, ..., 1000).
- Comparador de respuestas para detectar diferencias sutiles.
ZAP (OWASP Zed Attack Proxy)
- Escaneo automático de endpoints con parámetros.
- Fuzzing integrado para identificar respuestas inesperadas.
- Ideal para pruebas iniciales en entornos restringidos.
Autorización (extensión de Burp Suite)
- Detecta automáticamente brechas en autorización.
- Compara respuestas entre usuarios con distintos roles.
- Muy útil para identificar casos donde un usuario normal accede a contenido de admin.
SecLists
ids.txt- Lista predefinida de valores comunes (secuenciales, UUIDs, etc.).
- Usada con Intruder o en scripts personalizados.
- Disponible en: https://github.com/danielmiessler/SecLists
Scripts personalizados (Python, Bash)
- Automatización rápida para atacar APIs específicas.
- Ideal para pruebas controladas o PoCs.
- Ejemplo: uso de
requestspara iterar IDs con sesión autenticada.
5. Ejemplo conceptual
Supón que una app de facturación tiene este endpoint:
GET /api/invoices/555 HTTP/1.1
Host: billing.example.com
Authorization: Bearer user_session_xyzLa respuesta:
{
"id": 555,
"user_id": 2001,
"amount": "1250.00",
"date": "2025-03-15",
"details": "Servicio de hosting anual"
}Un atacante cambia 555 por 556, 557, etc. Si el servidor solo verifica autenticación, no autorización, puede obtener facturas de otros usuarios.
No hace falta SQLi, solo manipulación de referencias directas.
6. Laboratorio controlado
He desarrollado una aplicación Django vulnerable a IDOR para fines educativos. El código y pruebas están disponibles en: github.com/wh01s17/idor_vulnerable
# Clonar y arrancar
git clone https://github.com/wh01s17/idor_vulnerable
cd idor_vulnerable
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver 0.0.0.0:8000La app tiene:
- Dos usuarios: Alice (ID: 1) y Bob (ID: 2).
- Cada uno con sus facturas (
/invoices/). - Endpoint vulnerable:
GET /invoices/<id>/
Escenario de ataque (Bob → Alice)
Bob inicia sesión:
curl -c cookies.txt -X POST http://localhost:8000/login/ \
-d "username=bob&password=bob123"Consulta su factura:
curl -b cookies.txt http://localhost:8000/invoices/2/
# Respuesta: {"id": 2, "user_id": 2, "amount": "350.00", ...}Intenta acceder a la factura de Alice (ID 1):
curl -b cookies.txt http://localhost:8000/invoices/1/
# ¡Éxito! Respuesta: {"id": 1, "user_id": 1, "amount": "1200.00", ...}El backend no valida:
# 🚫 Vulnerable: no comprueba user_id
invoice = get_object_or_404(Invoice, id=invoice_id)Solución correcta:
# ✅ Segura: vincula al usuario autenticado
invoice = get_object_or_404(Invoice, id=invoice_id, user=request.user)7. Relación con Broken Access Control
| Aspecto | IDOR (Insecure Direct Object Reference) | Broken Access Control (BAC) |
|---|---|---|
| Definición | Acceso a objetos vía manipulación directa de IDs | Falta de validación de permisos en cualquier operación |
| Nivel de granularidad | Más específico: ataca objetos individuales (facturas, perfiles) | Más amplio: incluye IDOR, funcionalidades, rutas, APIs |
| Vector principal | Parámetros en URL, body o headers | Cualquier punto donde se salta autorización (roles, scopes) |
| Puede incluir | Cambio de user_id=123 en una petición | Acceso a /admin siendo usuario normal |
| Ejemplo típico | GET /user/123 → ver perfil ajeno | GET /api/deleteAllUsers → sin permisos |
| En OWASP Top 10 | Se reporta como una manifestación de BAC | Categoría A01 en OWASP Top 10 2021 y 2025 |
| ¿Es IDOR un BAC? | Sí, es un subtipo común de Broken Access Control | No, BAC es la categoría general |
💡 Conclusión: IDOR es una manifestación específica de Broken Access Control. Hoy se reporta bajo A01 en OWASP, pero sigue siendo un nombre clave en pentesting.
8. Patrones de detección
- Múltiples requests al mismo endpoint (
/user/X,/invoice/X) desde la misma IP. - Series de códigos
200 OKpara IDs distintos en rápida sucesión (fuzzing). - Respuestas válidas para IDs no pertenecientes al usuario autenticado.
- Códigos
403 Forbiddensolo cuando se accede a IDs muy altos o extremos (indicando intentos bloqueados). - Logs de aplicación mostrando acceso a
user_id=100siendo usuario101. - Actividad fuera del rango normal (ej: usuario normal accede a
?admin=true).
Ejemplo de línea de access_log (Django):
"GET /invoices/101/ HTTP/1.1" 200 821 "user=bob"
"GET /invoices/102/ HTTP/1.1" 200 902 "user=bob"
"GET /invoices/103/ HTTP/1.1" 200 762 "user=bob"
# Bob (user 2) accediendo a facturas de usuarios 101-103 -> clara señal de IDORComandos de monitoreo:
# Ver últimas 50 peticiones a /invoices/
grep "/invoices/" logs/django.log | tail -50
# Contar cuántos IDs distintos ha consultado una IP
grep "192\.0\.2\.10" access.log | grep "/invoices/" | grep -o "/[0-9]*" | sort | uniq -c
# Detectar usuarios que acceden a muchos objetos
awk '{print $NF}' access.log | sort | uniq -c | sort -nr | head
# último campo = usuario; contar accesos por user9. Mitigación
Validar siempre el ownership en el backend:
# Django (correcto)
invoice = get_object_or_404(Invoice, id=invoice_id, user=request.user)Usar identificadores no guessables (UUIDs):
- Evita secuencias predecibles:
user-8a3f9d2c-e1b4-4c1f-8f3a-d5d7c1b8e9a1 - No elimina IDOR, pero dificulta el fuzzing.
Control de acceso basado en rol (RBAC):
if request.user.role == 'admin'antes de ejecutar acciones sensibles.
Implementar ABAC (Attribute-Based Access Control) en sistemas complejos:
- Evaluar políticas por atributos: departamento, geolocalización, etc.
No exponer IDs directos si no es necesario:
- Mapear internamente:
/docs/share/abc123→ ID 999 en DB.
Monitoreo de comportamiento anómalo:
- Alertas por acceso rápido a múltiples recursos.
- Uso de SIEMs para correlacionar acceso y roles.
Pruebas de autorización en cada capa:
- No confiar solo en el frontend: el backend debe validar todo.
Auditar APIs con herramientas de pruebas de acceso:
- Usar Burp Suite + Autorización extension.
- Probar con múltiples usuarios simulados.
Registro completo de acceso a recursos sensibles:
- Loggear:
user_id,target_id,endpoint,timestamp,resultado.
Ejemplo de middleware de autorización (Django):
def owner_required(model, id_param):
def decorator(view_func):
def wrapper(request, *args, **kwargs):
obj_id = kwargs[id_param]
obj = get_object_or_404(model, id=obj_id)
if obj.user != request.user:
return HttpResponseForbidden("Acceso denegado")
return view_func(request, *args, **kwargs)
return wrapper
return decorator
# Uso:
@owner_required(Invoice, 'invoice_id')
def invoice_detail(request, invoice_id):
...10. Explotación documentada
10.1 107-quick-3
El identificador del perfil se incluye en la URL. Al sustituirlo por otros valores, el servidor devuelve perfiles de clientes distintos y expone pares de usuario y contraseña. El hallazgo se valida comparando la identidad de la sesión con el propietario del objeto devuelto, no solamente observando que el identificador sea predecible.
10.2 05-darkhole_1
La petición de cambio de contraseña contiene el identificador del usuario objetivo. Al modificarlo por el identificador de la cuenta administrativa, el backend aplica el cambio sin comprobar que la sesión tenga autorización sobre esa cuenta. Este caso afecta a la integridad y produce Horizontal o Vertical Privilege Escalation según el modelo de roles de la aplicación.
11. Clasificación
- Tipo: Insecure Direct Object Reference / Broken Access Control
- CWE:
- CWE-639: Authorization Bypass Through User-Controlled Key