Imagina que tu banco te muestra el extracto de cuenta en la URL https://banco.com/cuenta?id=8472. Cambias el número por 8473 y aparece el extracto de otra persona. No hackeaste el servidor, no explotaste ningún buffer overflow ni inyectaste código: simplemente cambiaste un dígito. Eso es un IDOR, y es exactamente el tipo de error que convierte a un desarrollador descuidado en el protagonista involuntario de una brecha de datos masiva.
El control de acceso roto (Broken Access Control) es la vulnerabilidad número uno del mundo web. OWASP la colocó en el puesto A01 de su Top 10 en 2021 y sigue en primera posición en el OWASP Top 10:2025 (la edición vigente desde noviembre de 2025), donde se la cataloga como A01:2025 – Broken Access Control. Un cambio importante de esta edición: la categoría ha absorbido el SSRF (Server-Side Request Forgery, CWE-918), que en 2021 era una categoría independiente (A10:2021). OWASP lo justifica porque, en el fondo, el SSRF es un fallo de control de acceso: el atacante obliga al servidor a hacer peticiones que no debería poder hacer. El SSRF se trata en detalle en el Módulo 6 de este curso; aquí solo conviene saber que, oficialmente, ya forma parte de esta misma familia. En este módulo vas a entender por qué ocurre el control de acceso roto, cómo se explota en laboratorio y, sobre todo, cómo se diseña software que lo evite desde el principio. Si estás preparando el eJPT, el OSCP o quieres entrar en el mundo del bug bounty, el control de acceso es una de las áreas con mayor retorno: es frecuente, a menudo crítica y, históricamente, subestimada por los desarrolladores.
Aviso legal y ético obligatorio (España, art. 197 bis CP): Todo lo que se describe en este módulo debe practicarse exclusivamente en laboratorios legales: OWASP Juice Shop en local, DVWA, las prácticas de PortSwigger Web Security Academy, o máquinas virtuales propias. Ejecutar estas técnicas contra sistemas de terceros sin autorización expresa y por escrito constituye un delito tipificado en el artículo 197 bis del Código Penal español, con penas de hasta dos años de prisión (hasta cinco si se accede a datos protegidos). Conocer el ataque es el primer paso para defenderse de él; usarlo fuera del lab es otra historia.
Qué aprenderás en este módulo
- Qué es el control de acceso roto y por qué ocupa el primer lugar (A01:2025) del OWASP Top 10.
- Qué son los IDOR y cómo se manifiestan en URLs, parámetros, cabeceras y APIs.
- La diferencia entre escalada de privilegios horizontal y vertical, y por qué importa.
- Qué es el forced browsing y el control de acceso a nivel de función.
- Una introducción al mass assignment y su relación con el control de acceso.
- Laboratorio paso a paso en Juice Shop y PortSwigger: manipular IDs, cambiar roles, acceder a rutas de administración con Burp Suite.
- Cómo prevenir estas vulnerabilidades en el servidor: denegar por defecto, RBAC, UUIDs, comprobaciones por objeto y por acción.
1. Broken Access Control: la vulnerabilidad número uno
El control de acceso es el mecanismo que decide qué puede hacer cada usuario dentro de una aplicación. Cuando ese mecanismo falla —o directamente no existe— se habla de Broken Access Control. La definición de OWASP es precisa: «Las políticas de control de acceso impiden que los usuarios actúen fuera de los permisos previstos. Los fallos suelen conducir a la divulgación no autorizada de información, a la modificación o destrucción de todos los datos, o al desempeño de funciones de negocio fuera de los límites del usuario».
En la edición 2021 del OWASP Top 10 subió desde la quinta posición hasta la primera, desbancando a la inyección SQL, y en el OWASP Top 10:2025 se mantiene como A01. El motivo es estadístico: según los datos oficiales de la edición 2025, el 100% de las aplicaciones analizadas presentaban alguna forma de control de acceso roto (frente al 94% que se citaba con los datos de 2021), con una tasa de incidencia media del 3,74% y máxima del 20,15% sobre el conjunto de CWE de la categoría. No es una vulnerabilidad esotérica; es endémica.
Los patrones más comunes que incluye OWASP en esta categoría son:
- Acceder a cuentas o datos de otros usuarios mediante la manipulación de identificadores (IDOR).
- Elevar privilegios accediendo a funcionalidades de administrador (escalada vertical).
- Acceder a rutas o recursos no enlazados pero accesibles (forced browsing).
- Modificar en masa atributos del modelo de datos que no deberían ser editables por el usuario (mass assignment).
- Ausencia de controles de acceso en la API cuando se accede por métodos alternativos (GET en lugar de POST, por ejemplo).
- Ejecución de peticiones en nombre de otro usuario (CSRF, CWE-352, cuando el control de acceso falla a nivel de sesión).
- Forzar al servidor a solicitar recursos no autorizados, típicamente internos (SSRF, CWE-918), incorporado a esta categoría en 2025.
- Exposición de información sensible a un actor no autorizado (CWE-200) o a través de datos enviados (CWE-201).
En total, OWASP mapea 40 CWE distintos bajo A01:2025, lo que da idea de la amplitud de la categoría: no es un único bug, sino toda una familia de fallos de autorización.
2. IDOR: referencias directas a objetos inseguras
Un IDOR (Insecure Direct Object Reference) ocurre cuando una aplicación usa un identificador controlado por el usuario —un número, un nombre de archivo, un hash corto— para acceder directamente a un objeto interno (un registro de base de datos, un archivo, un pedido), sin verificar que el usuario autenticado tiene derecho a acceder a ese objeto concreto.
El patrón más simple es numérico y secuencial:
GET /api/orders/1042 HTTP/1.1
Host: tienda.ejemplo.com
Authorization: Bearer eyJhbGc...
Si el servidor devuelve el pedido sin comprobar que el pedido 1042 pertenece al usuario del token, cualquier usuario autenticado puede enumerar /api/orders/1041, /api/orders/1043, etc. y leer todos los pedidos de la tienda. El atacante solo necesita un token válido propio y un bucle.
Los IDOR no se limitan a identificadores numéricos. Aparecen en:
- Parámetros de URL:
/profile?user_id=4921 - Cuerpos de petición JSON/POST:
{"account": "ES7621000418401234567891"} - Cabeceras personalizadas:
X-User-ID: 4921 - Nombres de archivo:
/files/informe_cliente_4921.pdf - Parámetros opacos pero predecibles: tokens Base64 que al decodificar revelan un ID interno (
eyJ1c2VyIjo0OTIxfQ==→{"user":4921}).
Por qué el servidor lo permite
La causa raíz es siempre la misma: el servidor confía en que el cliente solo pedirá lo que le pertenece, o comprueba que el usuario está autenticado (¿está logueado?) pero no que está autorizado (¿tiene permiso sobre ESTE objeto?). Son dos cosas distintas. La autenticación responde a «¿quién eres?»; la autorización responde a «¿qué puedes hacer?».
3. Escalada de privilegios: horizontal vs. vertical
La distinción entre escalada horizontal y vertical es fundamental tanto para entender el impacto de cada vulnerabilidad como para comunicarlo correctamente en un informe de pentesting o en un reporte de bug bounty.
Escalada horizontal
En la escalada horizontal el atacante accede a recursos de otro usuario con el mismo nivel de privilegios. No obtiene más permisos, pero accede a datos que no le corresponden. El IDOR del ejemplo del pedido es escalada horizontal: el atacante sigue siendo un cliente, pero puede leer los pedidos de otros clientes.
Usuario A (cliente): /api/profile/1001 → sus propios datos ✓
Atacante (cliente): /api/profile/1002 → datos del Usuario B ✗ (IDOR horizontal)
Escalada vertical
En la escalada vertical el atacante accede a funcionalidades o datos reservados a un rol superior: de usuario a administrador, de empleado a supervisor, de cliente a soporte. El impacto potencial es mayor porque el atacante gana capacidades que no tenía.
Atacante (usuario): GET /admin/users → lista de todos los usuarios ✗
Atacante (usuario): POST /admin/deleteUser → eliminar cualquier cuenta ✗
En la práctica, las dos pueden encadenarse: primero IDOR horizontal para leer los datos de otro usuario (incluyendo su token de sesión o credenciales), después escalada vertical al suplantar a ese usuario con mayores privilegios. Este encadenamiento aparece frecuentemente en reportes de bug bounty de alta severidad.
4. Forced browsing y control de acceso a nivel de función
El forced browsing (navegación forzada) consiste en acceder directamente a URLs o rutas que no están enlazadas en la interfaz de usuario pero que sí existen en el servidor. La aplicación asume —erróneamente— que si un recurso no aparece en el menú, nadie lo encontrará. La seguridad por oscuridad no es seguridad.
# Rutas típicas de forced browsing en aplicaciones web:
/admin
/admin/users
/dashboard/reports
/api/internal/config
/backup/db_2025-12-01.sql
/debug
/phpinfo.php
El control de acceso a nivel de función es el principio opuesto correcto: cada función o endpoint del servidor debe verificar de forma independiente que el usuario tiene el rol o permiso necesario para ejecutarla, independientemente de cómo llegó a esa URL. Si el panel de administración solo comprueba si el usuario es administrador en el menú de navegación (frontend) pero no en cada llamada al servidor (backend), cualquier usuario que conozca la URL puede ejecutar funciones administrativas.
5. Mass assignment (introducción)
El mass assignment es un patrón de vulnerabilidad que ocurre cuando el servidor acepta y aplica en masa los campos enviados en el cuerpo de una petición, sin filtrar cuáles puede modificar el usuario. Un formulario de registro envía nombre y contraseña; pero si el objeto de usuario tiene también un campo is_admin o role, un atacante puede intentar incluirlo en la petición:
POST /api/users/register HTTP/1.1
Content-Type: application/json
{
"username": "atacante",
"password": "s3cur3",
"is_admin": true,
"role": "superuser"
}
Si el framework ORM asigna todos los campos del cuerpo sin una lista blanca explícita (allowlist), el atacante acaba de darse privilegios de administrador. En Ruby on Rails fue tan prevalente que la mitigación (strong parameters) se integró en el framework. En Node/Express con Mongoose, en PHP con Eloquent o en Python con Django, el riesgo existe si no se usa serialización con campos explícitos. La relación con el control de acceso es directa: el mass assignment es un vector para la escalada vertical.
6. Laboratorio paso a paso
Esta sección cubre dos entornos complementarios: OWASP Juice Shop (instalación local para exploración libre) y los labs de PortSwigger Web Security Academy (guiados y gratuitos). Ambos son legales, seguros y específicamente diseñados para aprender. Necesitarás Burp Suite Community Edition en ambos casos.
Configuración previa
- Instala Juice Shop con Docker:
docker run --rm -p 3000:3000 bkimminich/juice-shop. Accede enhttp://localhost:3000. - Para PortSwigger: crea una cuenta gratuita en portswigger.net/web-security y accede a los labs desde el navegador.
- Abre Burp Suite. Configura el proxy en
127.0.0.1:8080y apunta tu navegador (o el navegador integrado de Burp) a ese proxy. Asegúrate de que el certificado CA de Burp está instalado en el navegador para ver tráfico HTTPS.
Lab 1 — Juice Shop: acceder al carrito de otro usuario (IDOR horizontal)
Este ejercicio se corresponde con el reto oficial «View Basket» (2 estrellas) de Juice Shop y demuestra cómo manipular el identificador de carrito para acceder al de otro usuario. La aplicación guarda tu bid (basket ID) en el Session Storage del navegador y lo usa para construir la petición a /rest/basket/{id}; al ser un entero, basta cambiarlo. Puedes editarlo desde las DevTools (pestaña Application → Session Storage) o, como se muestra aquí, interceptando y reenviando la petición con Burp.
- Regístrate con una cuenta propia (por ejemplo,
atacante@lab.com) y haz login. - Añade cualquier producto al carrito. Con Burp activo, observa en el HTTP History la petición que se genera:
GET /rest/basket/6 HTTP/1.1
Host: localhost:3000
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Cookie: token=eyJhbGciOiJSUzI1NiJ9...
- El número
6es el ID de tu carrito. Haz clic derecho sobre esa petición en Burp → Send to Repeater (Ctrl+R). - En la pestaña Repeater, cambia el
6por1,2,3… y pulsa Send en cada uno. - Observa las respuestas. Para los IDs que existen, el servidor devuelve
200 OKcon el contenido del carrito de otro usuario, incluyendo los productos que tiene añadidos. El servidor no verifica que el carrito solicitado pertenece al usuario del token.
HTTP/1.1 200 OK
{
"status": "success",
"data": {
"id": 1,
"UserId": 1,
"Products": [...]
}
}
Lab 2 — Juice Shop: encontrar y acceder al panel de administración (forced browsing + escalada vertical)
- Abre las herramientas de desarrollador del navegador (
F12) y ve a la pestaña Sources (Chrome) o Debugger (Firefox). - Localiza el archivo
main.js(el bundle JavaScript de la aplicación) y búscalo conCtrl+F. Busca la cadenaadministration. - Encontrarás una ruta declarada en el router de Angular:
path: 'administration'. Navega directamente ahttp://localhost:3000/#/administration. - Con tu cuenta de usuario normal, el servidor devuelve un error
403 Forbidden. Bien: el servidor tiene algún control de acceso a nivel de función para esta ruta. - Para entrar como administrador necesitas primero obtener sus credenciales: Juice Shop no publica una contraseña por defecto. La vía prevista es la del reto «Login Admin», explotando una inyección SQL en el formulario de login (por ejemplo, usuario
' OR 1=1--, técnica del Módulo 4), o bien volcando el hash MD5 de la contraseña del admin por SQLi y crackeándolo. Con esas credenciales válidas, inicia sesión y vuelve a navegar a/#/administration: ahora accedes al panel de administración completo. - Reflexión: el control de acceso a la ruta existe, pero depende por completo de la confidencialidad de las credenciales. Este ejercicio encadena dos módulos —SQLi (M4) para obtener la cuenta y control de acceso para usarla— e ilustra que la seguridad en capas importa: ni la ruta debería ser trivial de descubrir, ni un único fallo (un login inyectable) debería bastar para llegar al panel.
Lab 3 — Juice Shop: publicar una reseña como otro usuario (reto «Forged Review»)
- Con tu cuenta de usuario, deja una reseña en cualquier producto. Captura la petición en Burp:
PUT /rest/products/1/reviews HTTP/1.1
Host: localhost:3000
Authorization: Bearer eyJhbGc...
Content-Type: application/json
{"message": "Producto genial", "author": "atacante@lab.com"}
- Envía esa petición al Repeater. Cambia el campo
authorpor el email de otro usuario registrado (por ejemplo,victim@lab.com). - El servidor acepta la petición y publica la reseña en nombre de la víctima. No verifica que el campo
authordel cuerpo coincide con el usuario autenticado en el token JWT.
Lab 4 — PortSwigger: IDOR en chat logs (ficheros estáticos)
Accede al lab oficial de PortSwigger: Lab: Insecure direct object references.
- El lab simula una aplicación de atención al cliente con transcripciones de chat descargables. Cada chat se almacena como un fichero estático en el servidor con un nombre numérico.
- Inicia un chat con el asistente y descarga la transcripción. Observa en Burp la petición generada:
GET /download-transcript/2.txt HTTP/1.1
Host: [lab-id].web-security-academy.net
- Envía la petición al Repeater y prueba con
1.txt:
GET /download-transcript/1.txt HTTP/1.1
- La respuesta contiene la transcripción del chat de otro usuario, que incluye la contraseña de
carlosenviada por el asistente durante una conversación de soporte técnico. Usa esa contraseña para iniciar sesión comocarlosy completar el lab.
Lab 5 — PortSwigger: control de acceso a nivel de función (escalada vertical)
PortSwigger ofrece varios labs de escalada vertical en la sección Access control vulnerabilities. El patrón general:
- Inicia sesión con una cuenta de usuario normal.
- Navega a la funcionalidad de administración directamente por URL (
/admin,/admin-panel,/manage/users). Algunos labs revelan la ruta en el código fuente HTML o en el JavaScript. - Intercepta con Burp la petición que el panel de admin hace al servidor para listar o modificar usuarios.
- Comprueba si el servidor valida el rol: envía la misma petición API con las credenciales de un usuario normal. Si el servidor responde con los datos de administración en lugar de un
403, la validación de rol no existe en el backend.
# Petición legítima del admin:
GET /admin/delete?username=victim HTTP/1.1
Cookie: session=admin_session_token
# Misma petición con sesión de usuario normal:
GET /admin/delete?username=victim HTTP/1.1
Cookie: session=normal_user_token
# Si devuelve 200, el control de acceso no existe en el servidor.
7. Cómo prevenirlo
La prevención del control de acceso roto no es una sola medida; es un principio de diseño que debe estar presente en cada capa de la aplicación. Las medidas siguientes son verificables, implementables y directamente mapeadas a las recomendaciones de OWASP.
Denegar por defecto en el servidor
El principio de deny by default (denegar por defecto) establece que si el sistema no tiene una regla explícita que permita una acción, la deniega. Es el principio opuesto al que siguen muchas aplicaciones inseguras, donde «si no está prohibido, está permitido». La lógica correcta en pseudocódigo:
// MAL: comprobación en el frontend, no en el servidor
if (user.isAdmin) { showAdminButton(); }
// BIEN: comprobación en el servidor en cada petición
function deleteUser(requestingUser, targetUserId) {
if (!requestingUser.hasRole('ADMIN')) {
throw new ForbiddenError('Access denied');
}
// proceder con la eliminación
}
Comprobación de autorización por cada objeto y por cada acción
La autenticación verifica la identidad; la autorización verifica el permiso. Deben coexistir en el servidor para cada petición que acceda a un recurso o ejecute una acción. El patrón correcto:
// Comprobación por objeto: ¿puede este usuario acceder a ESTE recurso?
function getOrder(requestingUser, orderId) {
const order = db.findById(orderId);
if (!order) throw new NotFoundError();
if (order.userId !== requestingUser.id && !requestingUser.hasRole('ADMIN')) {
throw new ForbiddenError();
}
return order;
}
// Comprobación por acción: ¿puede este usuario EJECUTAR esta acción?
function deleteUser(requestingUser, targetUserId) {
if (!requestingUser.hasRole('ADMIN')) throw new ForbiddenError();
db.deleteUser(targetUserId);
}
No confiar nunca en datos enviados por el cliente
Cualquier valor que llega desde el navegador —parámetros de URL, campos de formulario, cabeceras, cuerpos JSON, cookies— puede haber sido manipulado. El servidor no puede asumir que el campo user_id de una petición POST corresponde al usuario autenticado: debe derivarlo siempre de la sesión autenticada en el servidor.
// MAL: confiar en el user_id enviado en el cuerpo
app.post('/api/orders', (req, res) => {
createOrder(req.body.userId, req.body.items);
});
// BIEN: derivar el userId de la sesión autenticada
app.post('/api/orders', requireAuth, (req, res) => {
createOrder(req.session.userId, req.body.items);
});
Identificadores no predecibles: UUIDs
Los identificadores secuenciales (1, 2, 3…) facilitan enormemente la enumeración. Usando UUIDs v4 aleatorios (550e8400-e29b-41d4-a716-446655440000) se elimina la posibilidad de adivinar IDs válidos. Pero ojo: el UUID no sustituye a la comprobación de autorización; solo la hace más difícil de explotar sin esa comprobación. La defensa real siempre está en el servidor.
RBAC bien implementado
El control de acceso basado en roles (Role-Based Access Control) asigna permisos a roles, y roles a usuarios. Los roles deben definirse en el servidor y verificarse allí. Un RBAC bien implementado tiene:
- Roles con permisos mínimos necesarios (principio de mínimo privilegio).
- Verificación del rol en el servidor en cada endpoint sensible.
- Separación entre la UI (que puede ocultar botones) y el backend (que verifica el permiso independientemente).
- Registro de auditoría de todas las acciones privilegiadas.
Cuando los permisos dependen no solo del rol sino del contexto (propietario del recurso, departamento, hora, ubicación, estado del objeto), el modelo que mejor encaja es ABAC (Attribute-Based Access Control), que decide en función de atributos del usuario, del recurso y del entorno. Es justamente el control «por objeto» que evita el IDOR: la regla «solo el dueño del pedido puede verlo» es una política ABAC. En la práctica muchos sistemas combinan RBAC para las funciones (escalada vertical) y ABAC para la propiedad de los datos (escalada horizontal). OWASP recomienda centralizar esta lógica en un único mecanismo de autorización reutilizado por toda la aplicación, en lugar de repartir comprobaciones ad hoc por cada endpoint.
Pruebas automatizadas de control de acceso
Las comprobaciones de acceso deben incluirse en la suite de pruebas del proyecto como tests de regresión. Si un desarrollador elimina accidentalmente la verificación de rol en un endpoint, el test lo detectará antes de que llegue a producción:
# Ejemplo con pytest (Python):
def test_user_cannot_access_admin_endpoint(client, user_token):
response = client.get(
'/admin/users',
headers={'Authorization': f'Bearer {user_token}'}
)
assert response.status_code == 403
def test_user_cannot_read_other_user_order(client, user_token, other_user_order_id):
response = client.get(
f'/api/orders/{other_user_order_id}',
headers={'Authorization': f'Bearer {user_token}'}
)
assert response.status_code == 403
Herramientas como Autorize (extensión de Burp Suite) automatizan la detección de IDOR durante un pentest: repiten cada petición capturada con el token de otro usuario de menor privilegio y alertan si la respuesta es similar.
8. Ejercicio propuesto
Completa los siguientes retos en tu entorno de lab local. Documenta cada hallazgo con: URL/endpoint afectado, petición modificada, respuesta obtenida e impacto estimado si ocurriera en producción real.
- Juice Shop — View Basket (2 estrellas): Accede al carrito de otro usuario usando la técnica del Lab 1 de este módulo. Identifica cuántos carritos existen y cuántos tienen productos.
- Juice Shop — Manipulate Basket (3 estrellas): Diferencia entre ver el carrito y modificarlo. Intenta añadir un producto al carrito de otro usuario; el reto se resuelve por HTTP Parameter Pollution (enviar dos veces el parámetro
BasketIden el POST a basket items). - PortSwigger — User role controlled by request parameter: Busca este lab en la sección de Access Control de Web Security Academy. Analiza cómo el servidor determina el rol del usuario y qué campo puedes manipular.
- Investigación: Busca en HackerOne o Bugcrowd un reporte público de IDOR (filtro: «IDOR» o «Broken Access Control»). Lee el informe completo. ¿Cuál era el endpoint vulnerable? ¿Qué datos expuso? ¿Cuánto pagó el programa? Escribe un párrafo de análisis.
9. Errores comunes
| Error | Por qué falla | Solución |
|---|---|---|
| Ocultar rutas en el frontend pero no protegerlas en el backend | Burp o DevTools revelan las rutas en segundos; el servidor no valida | Verificar rol/permiso en cada handler del servidor |
Confiar en el user_id enviado en el cuerpo de la petición |
El cliente puede modificar cualquier campo del body | Derivar siempre el userId de la sesión autenticada en el servidor |
| Usar IDs numéricos secuenciales | Facilitan la enumeración automática | Usar UUIDs v4; no sustituye la comprobación de autorización |
| Comprobar autenticación pero no autorización por objeto | «¿Está logueado?» ≠ «¿Puede ver ESTE recurso?» | Añadir comprobación de ownership en cada consulta a DB |
| No registrar accesos denegados | Los intentos de enumeración pasan desapercibidos en los logs | Logear todos los 403 con IP, usuario, endpoint y timestamp |
| Asumir que la API interna no necesita control de acceso | Si el endpoint es alcanzable por la red, necesita control | Aplicar las mismas reglas a microservicios internos y APIs privadas |
Preguntas frecuentes
¿Cuál es la diferencia entre un IDOR y un fallo de autorización genérico?
Un IDOR es un subtipo específico de fallo de autorización. Todo IDOR es un fallo de autorización, pero no todo fallo de autorización es un IDOR. El IDOR ocurre cuando la referencia al objeto viene directamente del cliente (un ID en la URL, un nombre de archivo en el parámetro) y el servidor la usa sin validar si ese objeto pertenece al usuario. Un fallo de autorización genérico puede ocurrir en rutas que no usan referencias directas, como acceder a /admin/panel sin que ningún ID esté en juego. El término IDOR se popularizó precisamente por su aparición en el OWASP Top 10 de 2007; hoy PortSwigger y OWASP lo describen como una subcategoría del control de acceso roto, no como una clase aparte.
¿Los UUIDs hacen innecesaria la comprobación de autorización?
No. Los UUIDs dificultan la enumeración porque son estadísticamente imposibles de adivinar, pero no eliminan la necesidad de comprobación de autorización. Si un UUID se filtra (por un log, un error, o una referencia en otra respuesta), el acceso no autorizado sigue siendo posible si el servidor no verifica quién accede. Los UUIDs son una capa adicional de defensa en profundidad, no un sustituto del control de acceso. La regla es: UUID y comprobación de autorización por objeto, siempre.
¿El control de acceso roto es relevante para certificaciones como eJPT u OSCP?
Sí, y cada vez más. El eJPT incluye control de acceso dentro de las vulnerabilidades web evaluadas. En el OSCP, las máquinas web con paneles de administración expuestos o parámetros manipulables son frecuentes. En el mundo del bug bounty, el control de acceso roto es históricamente una de las categorías con mayor ratio de pago: los programas valoran los IDOR de datos sensibles entre 500 y varios miles de euros dependiendo del impacto. La guía Hacking Web: guía completa cubre el mapa de certificaciones y cómo encajan estas técnicas en el camino hacia el OSCP. Puedes explorar las opciones de formación estructurada en cursos y certificaciones.
¿Cómo se detecta el control de acceso roto en una auditoría automatizada?
Las herramientas de escaneo automático (OWASP ZAP, Burp Suite Scanner Pro) detectan algunos casos obvios, pero el control de acceso roto requiere en gran medida análisis manual o semiautomático. La razón es que el escáner no tiene contexto semántico: no sabe si /api/orders/1042 debería ser accesible para el usuario actual. La extensión Autorize para Burp es la herramienta semiautomática más usada: repite cada petición capturada con un token de privilegio inferior y compara las respuestas. También es recomendable revisar manualmente todos los endpoints que reciban identificadores y verificar que el backend implementa comprobaciones de ownership.
Recordatorio ético final: Las técnicas de este módulo —manipulación de IDs, acceso a rutas de administración, modificación de parámetros de usuario— son exactamente las que utilizan los atacantes reales. La diferencia entre un pentester y un delincuente informático no es técnica, es legal: el pentester tiene autorización por escrito, un alcance definido y un informe de hallazgos para el cliente. En España, el artículo 197 bis del Código Penal tipifica el acceso no autorizado a sistemas informáticos como delito. Practica en Juice Shop, en DVWA, en los labs de PortSwigger o en máquinas propias. Nunca en sistemas ajenos.
