Autenticación vs Autorización: La Discoteca y los Cadeneros
Objetivo de esta Guía
Entender por qué el "Control de Acceso Roto" se ha convertido en el Error #1 del mundo en el ranking de OWASP. Los programadores de hoy son buenos usando contraseñas complejas. Lo que hacen terriblemente mal es verificar quien eres una vez que ya entraste al sistema.
Confundir la diferencia entre Autenticación y Autorización es lo que permite que un estudiante de secundaria con un navegador web pueda robar la base de datos de millones de pacientes de un hospital moderno.
Esta guía no solo explica la teoría. Cubre los patrones de ataque más comunes (IDOR, escalada de privilegios, broken access control en APIs) y las defensas prácticas que todo desarrollador debería implementar. La guía conecta fallos de autorización frecuentes con controles que deben aplicarse en cada solicitud del backend.
El Concepto Fundamental: AuthN vs AuthZ
Para que nunca lo olvides, usaremos la analogía de la Discoteca Exclusiva.
Autenticación (Authentication - AuthN): Es el Guardia de Seguridad en la puerta de la calle. Te pide tu ID y confirma que la foto coincida con tu cara. Si coincide, te deja entrar al edificio. Eres quien dices ser.
Autorización (Authorization - AuthZ): Es el Cadenero de la Sala VIP en el segundo piso. Tu ya estas adentro de la discoteca (ya pasaste la Autenticación), pero cuando intentas subir al segundo piso, el cadenero te detiene y dice: "Tu pulsera es normal. Aqui solo entran VIPs. Acceso Denegado." Tienes permiso para hacer esto.
El Error Más Común
Los programadores novatos instalan al guardia de seguridad de la calle (Pantalla de Login), pero se les olvida poner cadeneros VIP en las puertas internas. El programador asume ciegamente: "Bueno, si ya logró entrar al edificio, significa que es un tipo bueno, hay que dejarlo pasear por donde quiera."
Este error es tan común que OWASP lo catálogo como A01: Broken Access Control en su Top 10 2021. No es un error nuevo, pero es el que más daño causa hoy en día porque:
- No hay herramienta automática que lo prevenga.
- Depende completamente de la lógica del programador.
- Los frameworks de desarrollo no lo resuelven por defecto.
Insecure Direct Object Reference (IDOR)
El tipo más infame, simple y destructivo de "Autorización Rota" se llama IDOR (Referencia Insegura a Objetos Directos). Ocurre cuando el servidor asume que si pides un archivo, es porque te pertenece.
El Escenario
Inicias sesión en tu cuenta de un Banco. Le das clic al botón de "Ver mi estado de cuenta de este mes". El sistema te muestra un archivo PDF con tus gastos.
Si miras la URL arriba en tu navegador, ves algo como esto:
banco.com/ver_pdf?recibo_id=100
El Ataque (IDOR)
Un Hacker no necesita escribir código maligno ni inyectar virus. Simplemente da clic en la URL, borra el número 100, escribe el número 101, y presiona Enter.
banco.com/ver_pdf?recibo_id=101
Que pasa en la cocina (El Backend)?
El Servidor recibe la orden. Verifica que el hacker tiene una sesión iniciada (Autenticación), así que dice: "Okay, estas logueado. Quieres el recibo 101. Aqui lo tienes!"
El Servidor olvido preguntarle al cadenero VIP: "Espera, este hacker tiene la sesión iniciada, pero el recibo 101 le pertenece a el, o le pertenece al CEO de la empresa?"
Al cambiar un simple número en la URL, el hacker acaba de robar los estados de cuenta bancarios de cada uno de los clientes del banco (102, 103, 104...). Sin tirar una sola línea de código, vulneró la empresa entera.
Donde Encontrar IDOR
Los IDORs aparecen en cualquier parámetro que identifiqué un recurso:
- IDs numericos en URLs:
/usuario/5,/factura/1234 - IDs en cuerpos JSON:
{"orden_id": 456} - Nombres de archivos:
/documentos/factura-juan.pdf - Tokens débiles:
{"token": "abc123"}donde el token es predecible - Parámetros en POST ocultos:
<input type="hidden" name="user_id" value="5">
IDOR Horizontal vs Vertical
IDOR Horizontal: El atacante accede a recursos de usuarios del mismo nivel. Ejemplo: un usuario normal ve las facturas de otro usuario normal.
IDOR Vertical (Escalada de Privilegios): El atacante accede a recursos de un nivel superior. Ejemplo: un usuario normal accede a funciones de administrador.
Ambos son fallos de autorización, pero el vertical es generalmente más severo.
Escalada de Privilegios
El Control de Acceso Roto no solo sirve para robar PDFs ajenos. Sirve para volverse Administrador (el Dueño de la Discoteca).
Security by Obscurity (El Escondite)
Un programador malo simplemente esconde el botón de "Borrar Usuarios" para que los clientes normales no lo vean en su pantalla. Piensa que si no lo ves, no puedes darle clic.
Pero el Hacker sabe como piensa un programador. El Hacker intercepta el tráfico web y le escribe una petición manual (POST) al mensajero:
POST /admin/borrar_usuario
Host: empresa.com
Cookie: session=normal_user_123
El Servidor recibe la orden. Como el Servidor no tiene un Cadenero VIP en la puerta trasera, dice: "Oh, alguien me mando la orden de borrar a un usuario. Okay, lo borraré." El Hacker, con su cuenta de cliente gratuita, acaba de borrar a un usuario del sistema.
La Regla de Oro: Ocultar botones en la interfaz gráfica (Frontend) jamás es seguridad. El servidor trasero (Backend) debe desconfiar de CADA orden que recibe, y verificar si la cuenta que la envía tiene el rol requerido para hacerlo en ese mismo milisegundo.
Tipos de Escalada de Privilegios
Escalada Vertical: De usuario normal a administrador. El atacante obtiene acceso a funcionalidades restringidas.
Escalada Horizontal: De usuario normal a otro usuario normal. El atacante accede a los datos de otro usuario.
Escalada por Manipulación de Token: El atacante modifica un token JWT o cookie para cambiar su rol:
// Token original (decodificado) {"user": "juan", "rol": "usuario", "iat": 123456} // Token manipulado {"user": "juan", "rol": "administrador", "iat": 123456}
Si el servidor no verifica la firma del JWT, el atacante puede cambiar su rol.
Path Traversal como Escalada
A veces la escalada de privilegios no es sobre roles sino sobre rutas. El atacante accede a archivos fuera del directorio permitido.
https://empresa.com/descargar?archivo=../../etc/passwd
Esto no es estrictamente autorización, pero es un fallo de control de acceso a nivel de archivos.
Mass Assignment (Asignación Masiva)
Ocurre cuando un framework automáticamente mapea los parámetros de una petición a los campos de un objeto en la base de datos. Si el desarrollador no específica que campos pueden ser asignados, el atacante puede modificar campos que no debería.
Ejemplo:
Una API para actualizar el perfil de usuario:
// Peticion esperada {"nombre": "Juan", "email": "juan@nuevo.com"} // Peticion modificada por el atacante {"nombre": "Juan", "email": "juan@nuevo.com", "rol": "administrador"}
Si el servidor mapea todos los campos del JSON directamente al modelo de usuario sin filtrar, el atacante se auto-asigna el rol de administrador.
Defensa: Usar DTOs (Data Transfer Objects) que especifican exactamente que campos se pueden modificar. Nunca pasar el cuerpo de la petición directamente al modelo de base de datos.
Broken Access Control en APIs
Las APIs son particularmente vulnerables a Broken Access Control porque:
- No tienen interfaz gráfica, por lo que no hay "botones ocultos" que den pistas.
- Los endpoints son directos y fáciles de enumerar.
- Los desarrolladores frecuentemente olvidan poner controles de acceso en endpoints nuevos.
- Las APIs usan tokens (JWT, API keys) que pueden ser robados o manipulados.
Ejemplo común:
Una API bancaria tiene estos endpoints:
GET /api/cuentas-- Lista mis cuentasGET /api/cuentas/1234-- Detalle de mi cuenta 1234POST /api/transferir-- Realizar una transferencia
Si el desarrollador verifica la autenticación (token válido) pero no la autorización (el token pertenece al dueño de la cuenta 1234), cualquier usuario autenticado puede ver cualquier cuenta.
Aprende más en: La guía completa de riesgos de API en api-security/RIESGOS-CONTROLES.md.
El Principio de Menor Privilegio
Es la filosofía de seguridad que dice: un usuario (o un proceso) debe tener solo los permisos minimos necesarios para realizar su trabajo, y nada más.
Aplicación práctica:
- Un usuario normal no debería poder ver la lista de todos los usuarios del sistema.
- Un usuario normal no debería poder borrar posts que no son suyos.
- Un usuario normal no debería poder cambiar su propio rol.
- Un usuario normal no debería poder acceder a la consola de administración.
En el código:
Cada función del Backend debe verificar explícitamente si el usuario actual tiene permiso para realizar la acción solicitada. No asumas nada.
def borrar_usuario(id_usuario_a_borrar): usuario_actual = obtener_usuario_de_sesion() # Verificar autorizacion EXPLICITA if usuario_actual.rol != 'admin': return error("No tienes permiso para borrar usuarios") # Ejecutar la accion db.borrar_usuario(id_usuario_a_borrar)
Modelos de Control de Acceso
Existen varios modelos para implementar autorización. Cada uno tiene sus casos de uso y vulnerabilidades.
RBAC (Role-Based Access Control)
RBAC parece simple, pero su mantenimiento se complica cuando los roles crecen sin revisión ni criterios claros.
El más común. Los usuarios tienen roles. Los roles tienen permisos.
Ejemplo: Roles: usuario, moderador, admin
usuariopuede: editar su perfil, crear posts, ver posts públicosmoderadorpuede: editar cualquier post, borrar posts, banear usuariosadminpuede: todo
Vulnerabilidades comunes:
- Escalada de rol no verificada
- Roles mal configurados
- Un usuario puede tener múltiples roles y la lógica de union de permisos es incorrecta
ABAC (Attribute-Based Access Control)
El acceso se concede basado en atributos del usuario, del recurso, y del contexto.
Ejemplo: "Un usuario puede editar un post si y solo si el usuario es el autor del post O el usuario tiene rol 'admin'."
Ventaja: Mucho más granular que RBAC. Desventaja: Más complejo de implementar y mantener.
ACL (Access Control Lists)
Cada recurso tiene una lista de usuarios y sus permisos.
Ejemplo: post:123 -> {juan: leer, editar}, maria: leer, admin: todo}
Vulnerabilidad: Las ACLs son difíciles de mantener a escala. Si la lista de usuarios cambia frecuentemente, las ACLs se vuelven obsoletas.
Defensas Contra Broken Access Control
La defensa contra Broken Access Control no es técnica, es arquitectónica. No hay una librería que puedas instalar y olvidarte. Es una disciplina de programación.
Patrón de Verificación Centralizada
Crea una función o middleware central que verifique la autorización para cada acción sensible. No disperses la lógica de autorización por todo el código.
def requiere_permiso(permiso): def decorator(func): def wrapper(*args, **kwargs): usuario = obtener_usuario_actual() if not usuario.tiene_permiso(permiso): return error("No autorizado", 403) return func(*args, **kwargs) return wrapper return decorator @requiere_permiso('borrar_usuarios') def borrar_usuario(id): # ...
No Exponer IDs Directos
En lugar de usar IDs numericos secuenciales en las URLs, usa identificadores opacos (UUIDs, hashes, slugs).
Mal: /api/factura/1234
Bien: /api/factura/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Un UUID no es seguridad por si mismo (si el atacante lo obtiene, puede acceder igual), pero hace que la enumeración sea impracticable. No puedes adivinar UUIDs como puedes adivinar IDs secuenciales.
Verificación de Propiedad (Ownership Check)
Cada vez que un usuario accede a un recurso, verifica que el recurso le pertenece.
def ver_factura(id_factura): factura = db.facturas.obtener(id_factura) usuario = obtener_usuario_actual() if factura.usuario_id != usuario.id and usuario.rol != 'admin': return error("No tienes permiso para ver esta factura", 403) return factura
Este chequeo debe hacerse en CADA endpoint que acceda a recursos de usuarios, no solo en algunos.
Pruebas de Autorización Automáticas
Escribe pruebas automatizadas que verifiquen la autorización:
Test: Usuario A intenta ver factura del Usuario B -> debe recibir 403
Test: Usuario no autenticado intenta ver factura -> debe recibir 401
Test: Admin ve factura de cualquier usuario -> debe recibir 200
Test: Usuario A ve su propia factura -> debe recibir 200
Estas pruebas son tan importantes como las pruebas de funcionalidad.
Rate Limiting en Endpoints Sensibles
Los endpoints de autenticación y autorización deben tener rate limiting para prevenir ataques de fuerza bruta.
Casos Reales de Broken Access Control
Caso Facebook (2018): Un investigador descubrió que podía acceder a cualquier cuenta de Facebook simplemente modificando un parámetro en la respuesta del servidor durante el flujo de "olvide mi contraseña". Podía leer mensajes privados, fotos, y publicaciones de cualquier usuario. Facebook pago $40,000 en bug bounty.
Caso Parler (2021): Después del asalto al Capitolio de EE.UU., activistas descargaron videos de Parler que mostraban evidencia del evento. Parler tenía un IDOR masivo: los videos públicos tenían IDs numericos secuenciales. Los activistas simplemente iteraron sobre los IDs y descargaron miles de videos que los usuarios habian marcado como privados pero que la API no verificaba la autorización.
Caso T-Mobile (2022): Un atacante encontró una API interna de T-Mobile que no requería autenticación. Podía consultar cualquier número de teléfono y obtener información personal del cliente. No era un IDOR clásico pero era un fallo de control de acceso total.
Modos de Falla con Autenticación/Autorización
Confiar en el Frontend para decisiones de acceso. Si el Frontend oculta un botón pero el Backend no verifica el permiso, el atacante bypassea el Frontend.
No validar la propiedad del recurso. Asumir que si el usuario esta autenticado, todo lo que pide le pertenece.
Usar IDs secuenciales o predecibles. Facilita la enumeración de recursos.
JWT sin verificar la firma. El atacante puede modificar cualquier campo del token.
No cerrar sesión en el servidor. Si la sesión solo se cierra en el Frontend (borrando el token del cliente), el token robado sigue siendo válido.
Permisos por defecto demasiado abiertos. Crear nuevos usuarios con permisos de administrador por defecto.
No invalidar tokens/sesiones ante cambios de permisos. Si un usuario pierde el rol de admin, su token actual debería invalidarse inmediatamente.
Autoevaluación
-
Un ataque de IDOR (cambiar números en la URL) es un fallo en la Autenticación o en la Autorización? Justifica tu respuesta.
-
Entras a la página de tu Universidad. Para ver tu boleta de calificaciones, la URL es
universidad.com/boleta?alumno_id=5000. Al cambiar el número a5001, la página te devuelve un error. Pero al cambiar a5002, te devuelve la boleta de tu amigo con todas sus calificaciones. Que error crítico de programación cometió el Backend? -
Por qué depender del código HTML/JavaScript (Frontend) para ocultar el botón rojo de "Borrar Base de Datos" a los usuarios normales es una defensa inútil contra un hacker profesional?
-
En términos de Severidad, si un atacante descubre un IDOR en un foro que le permite leer los "Borradores de Post" de otros usuarios antes de que los publiquen, versus un IDOR en un Banco que le permite leer las "Tarjetas de Crédito", ambos ataques tienen la misma gravedad corporativa? Explica.
-
Explica la diferencia entre Escalada de Privilegios Horizontal y Vertical. Da un ejemplo de cada uno.
-
Un equipo de desarrollo implementa RBAC con tres roles:
usuario,editor,admin. Descubres que cuando unusuariosolicita cambiar su propio rol aadminvia API, el servidor lo permite. Que falla de autorización específica esta ocurriendo y como se llama? -
Tu aplicación usa UUIDs para los IDs de los recursos en lugar de números secuenciales. Un desarrollador argumenta que "como los UUIDs no son adivinables, no necesitamos verificar la propiedad del recurso". Por qué esta lógica es peligrosa?
-
Durante una auditoría de código, encuentras el siguiente fragmento en el Backend de una aplicación de mensajeria:
def leer_mensaje(id_mensaje): mensaje = db.mensajes.obtener(id_mensaje) return mensaje.contenido
Que vulnerabilidad de autorización tiene este código y como la corregirias?
Fuentes oficiales y referencias
Consulta estas fuentes primarias para verificar y ampliar la información de esta guía.
En esta página
- Objetivo de esta Guía
- El Concepto Fundamental: AuthN vs AuthZ
- El Error Más Común
- Insecure Direct Object Reference (IDOR)
- El Escenario
- El Ataque (IDOR)
- Donde Encontrar IDOR
- IDOR Horizontal vs Vertical
- Escalada de Privilegios
- Security by Obscurity (El Escondite)
- Tipos de Escalada de Privilegios
- Path Traversal como Escalada
- Mass Assignment (Asignación Masiva)
- Broken Access Control en APIs
- El Principio de Menor Privilegio
- Modelos de Control de Acceso
- RBAC (Role-Based Access Control)
- ABAC (Attribute-Based Access Control)
- ACL (Access Control Lists)
- Defensas Contra Broken Access Control
- Patrón de Verificación Centralizada
- No Exponer IDs Directos
- Verificación de Propiedad (Ownership Check)
- Pruebas de Autorización Automáticas
- Rate Limiting en Endpoints Sensibles
- Casos Reales de Broken Access Control
- Modos de Falla con Autenticación/Autorización
- Autoevaluación