Autenticación y autorización
El tema de la Autenticación (AuthN) y la Autorización (AuthZ) es extremadamente importante debido a la frecuencia de vulnerabilidades que involucran a cualquiera de ellas. Dado que parecen surgir con tanta regularidad, por lo general significa que hay un poco de incertidumbre en torno a lo que son o incluso sólo lo que las causa.
A modo de recordatorio, cada trimestre abarca lo siguiente:
- Autenticación: ¿Quién es el usuario?
- Autorización: ¿A qué debe tener acceso el usuario?
A continuación los examinaremos por separado.
Autenticación (fallos de identificación y autenticación)
La autenticación incorrecta puede abarcar una gran variedad de vulnerabilidades, tales como:
- Ausencia de autenticación en una página o punto final específicos
- Falta de protección contra ataques de fuerza bruta (Credentials stuffing)
- Procesos inseguros de recuperación de cuentas/contraseñas
- Generación, validación, caducidad, transmisión o almacenamiento inseguros de tokens de autenticación.
- Validación incorrecta o falta de validación de que el usuario se ha autenticado con 2FA (Si procede)
El primer punto de la lista (Ausencia de autenticación) es, con mucho, el problema más común observado. Muchas veces, un desarrollador tendrá que anotar/configurar explícitamente el nivel de autenticación que debe requerir una página o un endpoint y ese paso puede pasarse por alto fácilmente.
Es una buena práctica asegurar que un sistema falle cerrado, en lugar de abierto. Por lo tanto, en lugar de anotar cada punto final con la información que requiere una sesión de usuario autenticada, el valor predeterminado debe ser que todas las rutas requieren una sesión de usuario autenticada a menos que se haya anulado específicamente. Hacer esto puede reducir drásticamente el margen de error.
Autorización (control de acceso interrumpido)
Los problemas de autorización pueden presentarse de varias formas diferentes que son muy comunes:
- Referencias directas inseguras a objetos (IDOR)
- Falta Control de Acceso a Nivel de Función (Falta AuthZ)
- Escalada de privilegios (horizontal o vertical)
Referencias directas a objetos inseguras
Los objetos suelen tener identificadores únicos (ID) que se utilizan como clave para referenciarlos. Cuando un usuario envía una solicitud para ver un pedido, una cuenta o algo similar, normalmente contiene este ID. Una "Referencia Directa Insegura a Objetos" ocurre cuando la aplicación falla al validar si el usuario (o la falta del mismo) debe ser capaz de acceder a ese objeto específico.
Falta el control de acceso a nivel de función
Otra vulnerabilidad realmente común es la ausencia de comprobaciones de autorización para una página o endpoint (en contraposición a un objeto).
Dependiendo del marco utilizado, es habitual que los desarrolladores tengan que comprobar la autorización en el controlador o anotar el punto final y especificar los requisitos necesarios para llamar al punto final.
Por desgracia, estos pasos adicionales también son muy fáciles de olvidar, lo que a menudo explica cómo acaban produciéndose algunas vulnerabilidades de autorización.
Recomendaciones
Por defecto, cerrado en lugar de abierto
Tanto en el caso de la autenticación como en el de la autorización, es importante el principio de optar por cerrado en lugar de abierto.
Dependiendo de su lenguaje/framework, es una buena práctica asegurarse de que por defecto todas las rutas de su aplicación requieran una sesión autenticada con los roles o permisos más altos posibles. Esto obliga al desarrollador a anular los requisitos de la ruta.
cs
// Ensure the default behaviour is to authenticate requests, and check if they are admin
[Authenticate]
[Authorize("Admin")]
public class SecureController : Controller
{
}
public class MyController : SecureController
{
// Overrides the Authorize attribute inherited to allow any user to access the page
[Authorize("User")]
public Page ShowUserProfile() {
}
// Can only be accessed by an Admin user
public Page ShowAdminPage() {
}
// Overrides the Authenticate and Authorize attribute to allow ME
[AllowAnonymous]
public Page ShowLoginPage() {
}
}
Imponer comprobaciones de autorización en los servicios
Cuando se accede a los datos, es extremadamente importante garantizar que todos los accesos a los datos apliquen las comprobaciones de acceso y autorización pertinentes de manera uniforme. Esto se consigue generalmente mediante el uso de un servicio de dominio.
Otros ejemplos
A continuación, ofrecemos una breve colección de ejemplos que muestran la diferencia entre autenticación y autorización seguras e inseguras.
C# - inseguro
Falta de autenticación
public class AdminController : Controller
{
// INSECURE: Does not check whether the user is logged in before showing an Admin page
public Page ShowAdminPage() {
}
}
Falta autorización