Nuestros desarrolladores estrellas han agotado sus depósitos de café, por su búsqueda todo el tiempo por la resolución, hasta que Édgar halló el resultado en Gogs por lo tanto ahora la compartimos con nosotros.
Solución:
Olvidé que mi respuesta anterior todavía estaba en Internet obteniendo algo de tracción … y está parcialmente mal, como me di cuenta más tarde.
Respuesta actualizada:
I thought about storing the token in a cookie, but that doesn't seem very safe.
Es lo suficientemente seguro, si se hace correctamente. Sí, la cookie seguirá siendo legible por cualquier persona que tenga acceso físico al sistema. Más sobre esto a continuación.
Dejemos una cosa clara, es absolutamente necesario almacenar algunos datos en el lado del cliente (navegador en este caso) y enviar estos datos con llamadas a la API para autenticar a los usuarios. Llamemos a estos datos “token”.
Cuando envía este token en llamadas a la API, cualquier persona que tenga acceso físico al sistema puede verlo. Además, no tiene sentido encriptarlo porque …
- Deberá descifrarlo antes de enviarlo, lo que hace que el string legible.
- Necesitarás almacenar el descifrado key también en el lado del cliente, lo que nos devuelve al mismo problema.
¿Cuales son las opciones? Honestamente, déjalo ser. La mayoría de los sitios web funcionan así (casi). A menos que el sitio web contenga información muy sensible. En ese caso, busque contraseñas basadas en el tiempo, contraseñas basadas en hardware, ¿quizás biometría? Estos métodos en su mayoría transfieren la responsabilidad de mantener de manera segura el keys al usuario.
Por supuesto, puede hacerlo más seguro. A continuación se ofrecen algunos consejos:
- Elimine el token del servidor después de un cierto período de tiempo / inactividad.
- Actualice el token en solicitudes aleatorias e invalide las anteriores.
- Permitir a los usuarios ver sesiones activas y eliminarlas.
- Vincúlelo a la IP del usuario, o algo difícil de replicar. Cada vez que un usuario inicie sesión con una IP diferente, solicite una contraseña.
Con eso en mente, hablemos de almacenar el token.
Solo necesitamos asegurarnos de que otros sitios web, scripts maliciosos y software no puedan acceder al token almacenado. (El usuario siempre puede leer el token, como se mencionó anteriormente).
Puede almacenarlo en cookies
o localStorage
. Ambos funcionan bien, pero localStore
está diseñado para almacenar datos más grandes. Cookies
Puede almacenar hasta 4096 bytes de datos, lo que es suficiente para almacenar token. Cookies
también ayuda cuando se trabaja en SSR (renderización del lado del servidor). Sin embargo, puede resultar complicado manejar las cookies en React. (Sugerencia: pruebe next.js, tiene soporte incorporado para cookies y SSR con React).
También puede especificar el tiempo de vencimiento en las cookies, si eso ayuda.
TL; DR: Utilizando Cookies
está perfectamente bien. Úselo correctamente.
Gracias a @ShayanSalehian por señalar esto: LocalStorage is subject to XSS and cookie is subject to CSRF. So I think using cookies + CSRF is the most secure way even in TokenAuthentication for storing tokens on client...
Respuesta anterior (alerta de spoiler, está parcialmente mal):
Esto es algo con lo que también tuve que lidiar. Perdí algunas noches de sueño en el proceso.
Descargo de responsabilidad: no soy un experto en seguridad. Solo un poco obsesionado (léase: paranoico).
Versión corta (para responder a su pregunta): Finalmente terminé usando window.localStorage para almacenar el token. Aunque no estoy convencido de que sea lo mejor que se puede hacer, no se trata solo de la parte de “almacenamiento”: lea la versión larga para comprender más.
Versión larga:
Primero, aclaremos algunas cosas. React se parece más a una aplicación móvil que a una página web / sitio web. No estoy hablando de React Native, me refiero a React.js.
¿Por qué digo que se parece más a una aplicación móvil que a un sitio web? Los sitios web tradicionales suelen utilizar la autenticación basada en sesiones, para lo cual los navegadores / servidores suelen estar preparados. Al parecer, es una tarea sencilla y sin problemas.
En una aplicación móvil (o aplicación independiente del lado del cliente), necesita mantener algún tipo de token para decirle al servidor “¡Oye, soy yo! Visité hace un tiempo. Aquí está mi tarjeta de identidad. ¿Déjame entrar, por favor?” . El problema es que es difícil mantener el token seguro en el extremo del cliente. Android en sí no proporcionó ninguna forma segura de almacenar el token de autenticación hasta Android v4.3. Eso tampoco era lo suficientemente seguro, por lo que introdujeron el almacén de claves respaldado por hardware hace un tiempo. Esta es la razón por la que algunas aplicaciones no funcionan (y aún no funcionan) con dispositivos rooteados. Lea más sobre esto aquí: https://stackoverflow.com/a/19669719/3341737
En comparación con una aplicación web React / independiente, Google (algo) controla el extremo del cliente de Android. Es comparativamente más fácil para ellos implementar un almacén de claves basado en hardware. En el caso de la aplicación web, hay toneladas de navegadores, con cientos de versiones y todo eso.
Volviendo a window.localStorage. Al igual que las cookies, localStorage está aislado para cada dominio. Dado que es una API más nueva, está diseñada de una mejor manera que las buenas cookies antiguas.
No tiene sentido encriptar el key (aunque puede ofuscarlo), ya que necesitará almacenar el descifrado key en algún lugar local también. Entonces, si alguien puede acceder al token, puede acceder al descifrado key así como.
El segundo aspecto de este problema (y por qué “almacenar” no es el único problema) es: ¿de quién realmente desea proteger el token?
- ¿Hombre en el medio? Utilice SSL.
- ¿Otros sitios web? No pueden acceder al almacenamiento local de su dominio.
- ¿Alguna persona? Verdadero. Pueden obtener fichas fácilmente si tienen físico acceso a la PC. Tener acceso físico prácticamente los convierte en usuarios (¿quieres proteger el token del usuario?). Teniendo en cuenta que la persona tiene acceso físico, no puede proteger el token incluso si de alguna manera lo almacena de forma segura.
¿Por qué no? Porque deberá enviar el token con cada solicitud, y los datos enviados con cada solicitud están disponibles en el inspector de red del navegador. Entonces, independientemente de dónde y cómo almacene el token, alguien con acceso físico a la PC puede robarlo.
¿Por qué no Cookie? Dos razones (1 en realidad):
- La cookie se envía con cada solicitud de forma predeterminada. Realmente no necesita esto porque solo necesita enviar el token durante las llamadas a la API (no las cargas de la página). Además, dado que está utilizando DRF (aplicable a cualquier backend de API RESTful), probablemente necesite enviar el token de una forma específica al servidor, que requiere un método personalizado de cualquier manera.
- window.localStorage es una pequeña API con la que trabajar (solo
window.localStorage.setItem('key', 'value')
). Además, la restricción de tamaño máximo es mucho mayor en comparación con las cookies.
Por lo tanto, window.localStorage me parece una opción factible. Ilumíname si tienes una mejor solución.
Dicho esto, esto no significa que no pueda mejorar la seguridad. Aqui hay algunas sugerencias:
- Invalidar / eliminar el token de la base de datos después de un cierto período de tiempo o después de un cierto período de inactividad.
- Envíe el token actualizado (también invalide el anterior) con solicitudes de manera suficientemente aleatoria y reemplace el token almacenado por uno nuevo.
- Otorgue acceso al usuario para eliminar los tokens guardados de su cuenta junto con la última actividad de cada token.
- Si está realmente (realmente) preocupado, vincule el token con la IP del usuario (o algo más que no se pueda clonar en otro sistema). Si el usuario inicia sesión desde un nuevo dispositivo / ubicación / navegador, use 2FA.
Al final de la artículo puedes encontrar las observaciones de otros gestores de proyectos, tú aún tienes el poder dejar el tuyo si lo deseas.