¿Cómo hago correos electrónicos de inicio de sesión seguros? (GET / POST) [duplicado]

3

Visión

Imagino un sistema de inicio de sesión / registro, donde el usuario ingresa su correo electrónico y recibe un correo electrónico con un enlace para iniciar sesión. El usuario hace clic en el enlace y se registra automáticamente (confirma la dirección de correo electrónico en el proceso).

Esto sería una forma de autenticación sin contraseña.

Problema

El problema que veo con este enfoque es que un enlace enviará una solicitud GET, pero esta solicitud cambiará el estado de la sesión del usuario (activándola).

Las solicitudes GET deberían (según el estándar HTTP) nunca tener efectos secundarios. Esto es algo que los exploradores también asumen, lo que significa que podrían obtener solicitudes GET para optimizar el rendimiento / la experiencia del usuario.

Supongamos que está utilizando Gmail en el navegador. ¿Podría suceder que el navegador obtenga el enlace en el correo electrónico?

Sería un gran problema de seguridad si simplemente abrir el correo electrónico fuera suficiente para iniciar sesión en el sitio.

Lo que he considerado

Uso de JavaScript en la página de destino para enviar una solicitud POST

Mi corazonada me dice que, aunque HTML / CSS / JavaScript de un enlace podría ser recuperado previamente, ninguno de este código (especialmente el JavaScript) se ejecutará antes de que el navegador abra explícitamente el enlace.

Esto debería significar que si la sesión de usuario se activa de alguna manera utilizando JavaScript (enviando una solicitud POST al backend), debería ser seguro usar una solicitud GET para llegar a esta página (como un enlace en el correo electrónico).

¿Estoy en lo cierto al asumir esto?

¿Es una mala práctica hacerlo de esta manera?

Usando un formulario HTML en el cuerpo del correo electrónico

Otra opción sería colocar un formulario en el correo electrónico, lo que permitiría una solicitud POST directamente desde el correo electrónico.

Sin embargo, parece que varios clientes de correo electrónico bloquearán los envíos de formularios dentro de los correos electrónicos. Los clientes de correo electrónico que permiten el envío de formularios tienden a advertir al usuario de que el correo electrónico es probablemente malicioso. Parece que esta no es realmente una buena solución.

    
pregunta Tobias Bergkvist 23.11.2018 - 03:09
fuente

1 respuesta

5

En primer lugar, los enlaces del correo electrónico cambian de estado todo el tiempo . Si bien los GET no idempotentes son una violación del estándar de jure, el estándar de facto es que cualquier navegador o sistema de correo electrónico que no permita que los usuarios realicen solicitudes GET para cosas como la verificación de correo electrónico, el restablecimiento de contraseñas y otros servicios diversos. El uso de inicio de sesión sin contraseña basado en correo electrónico (como Slack) es un navegador o cliente de correo que todo el mundo considerará roto. Otro ejemplo común es el enlace "cerrar sesión" (que en muchos sitios es solo un GET para enlace , sin siquiera protección CSRF); Si bien esto es potencialmente un riesgo de seguridad, en la práctica se usa mucho y es difícil de explotar como algo más que una broma.

CON LO QUE DICE la forma estándar de manejar esto es de manera segura si el enlace en el correo electrónico contiene un token (único aleatorio fuerte) que lleva al usuario a una página de destino y la página de destino dice, básicamente, "hey, parece ser [nombre de usuario], haga clic AQUÍ para iniciar sesión" junto con el enlace "No [nombre de usuario]? Haga clic AQUÍ" en un texto más pequeño debajo. El enlace enviado por correo electrónico expira después de que se haga clic en cualquiera de los enlaces de la página de destino, o después de que haya transcurrido un cierto período de tiempo (generalmente no más de una hora), lo que ocurra antes. Sin embargo, la carga de la página de destino no expira inmediatamente el enlace, y los "enlaces" en la página de destino pueden ser botones de forma segura en un formulario HTML que se envía a su servicio, o JavaScript se dispara. Los "enlaces" en la página de destino idealmente deberían tener protección CSRF.

Esto tiene algunas ventajas:

  • No hay problema si la página de destino se visita "antes de tiempo".
  • No hay forma de que un atacante engañe a alguien para que lo firme por accidente.
  • No se necesitan solicitudes GET que cambien de estado (aunque el evento JS podría simplemente desencadenar una navegación a una página impredecible de "completar este inicio de sesión", si no te importa esa parte de la especificación) .
  • Permite al usuario cancelar el inicio de sesión si hizo clic en el enlace por accidente o si tiene varias cuentas y usó la incorrecta por accidente.

También tiene algunas desventajas:

  • El usuario tiene que hacer clic en un tiempo adicional. Puedes mitigar esto si tienes un tiempo de espera que inicie sesión automáticamente al usuario después de unos segundos, si no hacen clic en nada o cierran la página.
  • El token enviado en la URL puede permanecer activo durante un período después de ser visitado. Esto es un riesgo porque las direcciones URL a veces se registran en lugares donde los usuarios que no son de confianza pueden verlas o son de otra manera expuestas. No creo que haya ninguna mitigación para esto (aparte de que el tiempo de vida sea muy corto) aparte de hacer que el enlace sea de un solo uso, que ambos rompen "los GET deberían ser idempotentes" (no es realmente un gran problema, como se explicó anteriormente) y "la precarga de esta URL no debe romper cosas" (ver arriba).

Por cierto, los servicios de correo web y los sistemas de chat basados en la web, etc., reescriben los enlaces en los mensajes recibidos (intente copiar el enlace real de un mensaje de Gmail, por ejemplo; el texto de la barra de estado es una mentira). Cuando hace clic en el enlace, obtiene un rebote a través de una página de redireccionamiento en otra pestaña, en lugar de abrir el destino en esa otra pestaña directamente. Esto evita que cosas como la página vinculada a usar la propiedad window.opener se metan con la página webmail / chat.

    
respondido por el CBHacking 23.11.2018 - 08:48
fuente

Lea otras preguntas en las etiquetas