Estoy desarrollando una aplicación en React y Spring Boot + Spring Security. En este momento, agregué HTTP Basic Auth para la autenticación de usuarios. El usuario ingresa el nombre de usuario y la contraseña en un formulario de inicio de sesión y los envío (por supuesto a través de HTTPS) a mi backend. Si el usuario está autenticado, devuelvo el éxito y la interfaz guarda las credenciales en el almacenamiento local para futuras solicitudes (es decir, sin sesión del lado del servidor). Luego, cada vez que navego a una ruta "segura" en React, verifico el almacenamiento local y luego uso las credenciales para mis solicitudes seguras. Cuando el usuario necesita cerrar sesión, la aplicación elimina las credenciales del almacenamiento local.
Es una implementación de seguridad muy trivial, pero a menos que tenga una vulnerabilidad XSS, o haya una degradación a HTTP (para mi dominio, no es posible: precarga de HSTS), no creo que sea vulnerable. Pero el principal problema que veo es que, por ejemplo, no puedo cerrar la sesión de los usuarios de forma remota, lo que podría ser útil en algún momento. ¿Me he encontrado en un callejón sin salida? ¿La autenticación básica HTTP no está diseñada para la autenticación sin estado con SPA?
Primero, sugeriría no hacer eso. Como dijiste, una degradación a HTTP expondrá las credenciales y una vulnerabilidad XSS hará posible que el atacante robe las credenciales de tus usuarios.
Sin embargo, si insiste en almacenar las credenciales en localStorage, debe asegurarse de varias cosas:
De esta forma, una degradación a HTTP expondrá el tráfico, pero las credenciales se transferirán después del cifrado.
Solo se puede acceder a localStorage a través de scripts que ingresan a través de su propio dominio, por lo que está seguro siempre que el único código de interfaz que se ejecute sea el suyo. Pero si se ejecuta cualquier otro código, mediante inyección o si comparte el dominio con otra persona, podrá acceder a los datos de almacenamiento local.
Para la segunda parte de su pregunta, cerrar la sesión de los usuarios de forma remota. Puedes implementarlo de otra manera:
Tras un inicio de sesión exitoso, genere una cadena completamente aleatoria no relacionada con las credenciales del usuario y guárdela en la base de datos, junto con una fecha de vencimiento. Luego, pase esa cadena para que se almacene en localStorage.
A partir de ese momento, siempre que esa credencial de almacenamiento local coincida con la de la base de datos y el tiempo de espera no haya expirado, automáticamente los considerará conectados.
De esta forma, no hay riesgo de exposición de las credenciales del usuario desde localStorage. Sin embargo, con esta cadena única temporal que funciona esencialmente como un ID de sesión, aún deberá conocer y tomar precauciones contra los riesgos asociados con el secuestro de sesión.
Ahora, para finalizar la sesión de un usuario de forma remota, puede actualizar la fecha de vencimiento de esa entrada en la base de datos.