Estoy desarrollando un SPA con back-end REST y quiero tener una autenticación simple basada en token. El objetivo para el respaldo de REST es ser apátrida. Explicaré el modelo de seguridad e intentaré hacer referencia a todas las fuentes para las decisiones que se tomaron durante el diseño. Querría un comentario sobre toda la configuración y responder a algunas preguntas específicas.
Abstract
La autenticación se realizará en un punto final dedicado (por ejemplo / auth / login). La información de inicio de sesión se pasará como un objeto JSON. La información contendrá nombre de usuario y contraseña. Al iniciar sesión correctamente, se emitirá un token JWT firmado. Este token se utilizará para el acceso posterior a la API REST.
La aplicación usará HTTPS y yo controlo todos los subdominios.
Especificaciones
JWT
- Contiene nombre de usuario, emitido a la hora de vencimiento
- Contiene notificaciones sobre la pertenencia a roles dentro de una aplicación
- Contiene un token CSRF (generado aleatoriamente desde un generador pseudoaleatorio criptográficamente seguro)
- Firmado con una clave HMAC (SHA256) solo disponible para el servidor
Expiración
Se emitirá un token con un breve tiempo de caducidad (por ejemplo, 30 minutos). Se emitirá un token actualizado con cada nuevo vencimiento en cada solicitud (vencimiento de ventana deslizante) con una fecha límite de algo razonable (por ejemplo, 8 horas). El flujo del proceso será el siguiente:
- La solicitud de inicio de sesión inicial emitirá un token con una caducidad de 30 minutos
-
La siguiente solicitud verificará si el token ha caducado. Si está vencido, se bloqueará el acceso. Si no, se cumplirá una solicitud. Se realizará una comprobación en ese momento sobre la edad del token.
- Si la edad está dentro de la fecha límite (menos de 8 horas), se generará un token actualizado que contiene un nuevo tiempo de caducidad por otros 30 minutos. Emitido en el momento seguirá siendo el mismo que en el token original.
- Si la antigüedad del token es la fecha límite de aprobación, no se generarán tokens actualizados y el usuario deberá iniciar sesión nuevamente.
Justificación: quiero proteger un token con un breve tiempo de caducidad en caso de que esté comprometido. Tampoco quiero forzar al usuario a volver a iniciar sesión a menudo. Un atacante tendría que solicitar un token nuevo en un período de tiempo inferior al tiempo de caducidad de un token. En caso de que un atacante logre hacer eso, la cantidad máxima de tiempo que él / ella puede usar el token está definida por la fecha límite. El usuario puede permanecer en línea durante un período de tiempo límite establecido. Para una solicitud de negocio, un plazo de 8 horas o un día es suficiente. ¿Es esta implementación lo suficientemente segura? ¿Cuáles son los posibles inconvenientes y vulnerabilidades?
Transporte y almacenamiento JWT
JWT se transportará como una cookie httpOnly al cliente y se almacenará en el repositorio de Cookies en el navegador.
Justificación: para proteger un token del ataque XSS que podría comprometer el token si se mantiene dentro de localStorage / sessionStorage. Esto es por una recomendación de este artículo . ¿Hay algún problema con este enfoque que no sea abrir la implementación a un ataque CSRF?
Protección CSRF
El almacenamiento de tokens JWT dentro de las cookies abrirá la implementación a un ataque CSRF. Para mitigar este problema, se implementa un método de envío doble de cookies. El token CSRF se genera e incluye dentro del token JWT. Este token también se suministra a la aplicación cliente en un objeto JSON de una respuesta a la solicitud de inicio de sesión. La aplicación almacenará CSRF en localStorage y lo enviará con cada solicitud dentro de un encabezado personalizado.
Justificación: según una respuesta a esta referencia a una pregunta this paper , para una protección CSRF efectiva es necesario para vincular criptográficamente el token CSRF con una cookie de identificación / autenticación de sesión. Si incluyo un token dentro de un JWT, ¿se considera que está vinculado criptográficamente a una sesión de seguridad?
Conceptualmente, ¿ve algo incorrecto en esta implementación?