Guías de seguridad
¿Añadiste un inicio de sesión y lo llamaste seguro? — autenticación frente a autorización
Autenticación (quién) frente a autorización (qué puedes hacer): un login sin datos acotados al propietario provoca 'con sesión = ve todo'. Por qué pasa y cómo defenderse.
"Añadí un inicio de sesión, así que ya está protegido" — esa es una suposición peligrosa. El inicio de sesión (autenticación) y los permisos (autorización) son cosas distintas, y confundirlos lleva a un incidente en el que todo el que inicia sesión puede ver todos los datos, incluidos los de otras personas. Aquí no hay pasos de ataque — solo cómo ocurre y cómo defenderse.
La autenticación y la autorización son cosas distintas
Se confunden con facilidad, pero sus papeles son completamente diferentes.
Solo autenticación (el error habitual)
- pensar "puede iniciar sesión = seguro"
- tratar las lecturas de datos tras el login igual para todos
- resultado: todo el que inicia sesión alcanza todos los datos
Autenticación + autorización (cómo debería ser)
- la autenticación confirma "quién"
- la autorización limita a "solo los datos que puede tocar"
- las lecturas de datos siempre están acotadas al propietario
La autenticación es "el control de identidad en la entrada"; la autorización es "controlar en qué salas puedes entrar." Un inicio de sesión solo garantiza lo primero. "Quién puede tocar qué datos" es algo que tienes que escribir por separado.
Cómo ocurre "ve todos los datos" en apps reales
En la práctica, el mismo fallo aparece una y otra vez en sistemas independientes hechos a mano. Una app personal de tareas/notas, o un pequeño sistema de gestión de productos/pedidos (con integraciones de API externas) — la causa era el mismo solapamiento de dos defectos.
① El registro está abierto (y en dos rutas)
Los scaffolds de autenticación (cosas como Breeze/Jetstream de Laravel) a menudo vienen con la página de registro pública por defecto. Y cuando la ruta de registro está duplicada entre la biblioteca de interfaz y el paquete de autenticación, cerrar una deja /register en pie. Un desconocido que conozca la URL puede darse de alta.
② La autenticación existe pero la autorización no (falta el acotado por propietario)
La tabla de datos no tiene columna de propietario (user_id), o las consultas de listar/leer/actualizar/borrar no están acotadas al usuario actual. Entonces "con sesión iniciada = acceso a todos los datos." Si la app inicia sesión automáticamente justo tras el alta, un desconocido aterriza sobre la lista de datos de otra persona en el momento en que se registra.
Resultado: el incidente authn ≠ authz
La entrada (login) está ahí, pero las llaves de las salas (autorización) no. Como el desconocido se comporta como "un usuario que inició sesión correctamente", apenas queda rastro de acceso no autorizado.
El radio de impacto es mayor cuanto más datos de negocio haya de por medio (registros de clientes, pedidos, claves de API de integraciones pueden verse afectados). Y un sistema distinto construido de la misma forma probablemente tenga el mismo fallo.
Cómo defenderse
Acota siempre los datos al propietario
Limita cada lectura y escritura a "las propias filas del usuario con sesión iniciada." Fuerza la condición de propietario en todas las operaciones de leer/actualizar/borrar mediante un scope global del ORM o una política de autorización (policy/gate). Si la tabla no tiene columna de propietario, rediseña eso primero.
Cierra el registro que no necesites — y sospecha de rutas duplicadas
Desactiva el alta en apps personales/internas. Comprueba de verdad por HTTP que /register y similares devuelven 404, y revisa ambas rutas de registro: la de la biblioteca de interfaz y la del paquete de autenticación.
Defensa en profundidad en las superficies de administración
Para uso interno/administrativo, no te fíes solo de la autenticación — añade capas como restricciones de IP, autenticación Basic y similares. Si un muro cae, el siguiente lo detiene.
Registros de auditoría y acceso *antes* de un incidente
Sin "quién, cuándo, desde qué IP, hizo qué" no puedes reconstruir "qué se vio" a posteriori. Como mínimo, conserva registros de auditoría de éxito/fallo de inicio de sesión y retén/rota los registros de acceso web.
Detecta nuevas altas y anomalías
La lección central aquí es "pasó desapercibido durante mucho tiempo." Añade formas de darte cuenta rápido — notificaciones al registrarse un nuevo usuario, recuentos periódicos de usuarios/datos. Sin detección, el fallo queda abierto en silencio.
La opinión de este sitio: una biblioteca solo garantiza el 'quién'
Una biblioteca de autenticación se ocupa del "quién" — nada más. "Qué puede hacer esa persona" no existe salvo que tú, el diseñador, lo escribas. Y — un fallo estructural encontrado en un sistema probablemente esté en otros sistemas construidos de la misma forma. No arregles uno y pares; audita las construcciones de la misma forma en todo el conjunto. Cuando no puedas saber si algo se leyó, la postura correcta es tratarlo como leído y revocar/rotar cualquier secreto expuesto.
Sigue leyendo
- Glosario: qué es IDOR (control de acceso roto) (el clásico: pasa el ID de otra persona y alcanza sus datos)
- Aplícalo: seguridad por framework (dónde escribir la autorización en cada framework)
- Relacionado: mantén los secretos fuera de los directorios públicos (comprobar la exposición de token/credenciales/.env)
- Fundamentos: proteger los secretos, desde cero / base: la lista mínima de seguridad
Fuentes
- OWASP Top 10 (2021) A01: Broken Access Control: owasp.org
- OWASP Authorization Cheat Sheet: cheatsheetseries.owasp.org
FAQ
Q¿En qué se diferencian la autenticación y la autorización?
La autenticación verifica quién eres (inicio de sesión). La autorización decide qué puedes hacer (permisos). Como analogía, la autenticación es el control de identidad en la entrada del edificio; la autorización controla en qué salas puedes entrar. Añadir un inicio de sesión solo implementa la autenticación — la autorización (quién puede tocar qué datos) es algo que debes escribir por separado. Confunde ambas y acabas con 'todo el que inicia sesión puede ver todos los datos'.
QHay inicio de sesión, entonces ¿por qué todos pueden ver todos los datos?
Porque la consulta de datos no está acotada a 'solo las filas del propio usuario con sesión iniciada'. Olvida la condición de propietario (user_id) en cualquiera de listar/leer/actualizar/borrar y, una vez que alguien inicia sesión, se devuelven todas las filas — incluidas las de otras personas. Es un fallo de diseño independiente de si existe autenticación, y es el clásico Broken Access Control que OWASP sitúa en el número uno.
QPara una herramienta personal o una app interna, ¿no pasa nada por dejar el registro abierto?
Es peligroso. Muchos scaffolds de autenticación vienen con el registro (p. ej. /register) público por defecto. Si un desconocido conoce la URL puede darse de alta, y sin autorización aterriza directamente sobre los datos de dentro. A veces las rutas de registro están duplicadas (tanto en la biblioteca de interfaz como en el paquete de autenticación), así que cerrar una no la cierra. Desactiva el registro que no necesites y añade capas de defensa como restricciones de IP en las superficies de administración.