¿Cómo implementar de forma segura una característica de "Recordarme"?

55

Suponiendo que ya tiene un sitio web que implementa todas las cosas de inicio de sesión estándar, ¿cuál es la manera más segura y correcta de permitir que los usuarios inicien sesión automáticamente durante un período de tiempo determinado (digamos 30 días)? Este período de tiempo debe ser estrictamente aplicado; es decir, no creo que una solución válida sea dar una fecha de vencimiento a una cookie y esperar que el navegador del usuario la elimine de manera oportuna.

Detalles del sistema de inicio de sesión existente:

  • Un usuario debe ingresar un nombre de usuario y contraseña
  • La base de datos almacena nombres de usuario así como también strong_hash_function (contraseña + user_specific_random_salt)
  • Los formularios de inicio de sesión se cargan y envían a través de SSL, al igual que todas las páginas subsiguientes

Hay muchos ejemplos y muchos con fallas de seguridad obvias. Usemos PHP como el idioma de destino, pero los conceptos deben ser aplicables a cualquier idioma.

    
pregunta colithium 11.11.2010 - 23:32
fuente

6 respuestas

30

Mi respuesta tiene dos partes:

Primero, suponiendo que su modelo de amenaza no se preocupe por la exposición de las cookies del lado del cliente , puede generar y almacenar un nonce en el lado del servidor. , computername, timestamp, cosas similares), y enviar eso en la cookie. El nonce debe almacenarse en la base de datos, junto con la fecha de caducidad, y ambos deben verificarse cuando vuelva la cookie.
Esta debe ser solo una cookie "recordatoria", NO una cookie de sesión, es decir, cuando obtiene esa cookie sin sesión, vuelva a emitir una nueva cookie de sesión regular. También tenga en cuenta que, al igual que la cookie de sesión, esta debería entregarse solo a través de https, y utilizando los atributos secure y httpOnly , y por supuesto tiene el ámbito de la cookie correctamente, etc.

Segundo, para los usuarios que fueron recordados, debería (probablemente, dependiendo de la sensibilidad) invocar un proceso de reautenticación para ciertas operaciones confidenciales. Es decir, a veces necesitarían ingresar su contraseña de nuevo de todos modos, pero rara vez, y solo para operaciones confidenciales. Esto es para prevenir ataques como CSRF y la exposición compartida de escritorio.

    
respondido por el AviD 11.11.2010 - 23:56
fuente
7

He escrito extensamente sobre seguro Inicio de sesión y casillas de verificación "Recuérdame" . La respuesta aceptada no es incorrecta, pero diría que es un poco más complicada en un aspecto de lo que debe ser, y descuida un área donde se necesita un poco más de complejidad.

  

genere y almacene un archivo nonce en el lado del servidor, haga un hash con el nombre de usuario y otra información (por ejemplo, la dirección IP del cliente, el nombre de computadora, la marca de tiempo, cosas similares) y envíe eso en la cookie. El nonce debe almacenarse en la base de datos, junto con la fecha de caducidad, y ambos deben verificarse cuando vuelva la cookie.

Por lo tanto, una implementación que no exponga ninguna información al cliente puede parecer ...

// Storage:
setcookie(
    'rememberme',
    hash_hmac('sha256', $username . $_SERVER['REMOTE_ADDR'], $storedNonce),
    time() + 8640000 // 100 days, for example
);
// Validation:
$valid = hash_equals(
    $_COOKIE['rememberme'],
    hash_hmac('sha256', $username . $_SERVER['REMOTE_ADDR'], $storedNonce)
);

La limitación obvia aquí es que, si su dirección IP (u otra información) cambia, su cookie no sirve para nada. Algunos pueden ver esto como algo bueno, lo veo como innecesariamente hostil hacia la facilidad de uso para los usuarios de Tor.

Ciertamente, puede interpretar que la cita anterior significa algo diferente, como el token JSON Web de un hombre pobre, también. Sin embargo, las cookies HTTP están limitadas a 4 KiB por dominio. El espacio es escaso.

Otro problema: ¿Cuánta información filtra su base de datos sobre su aplicación? (Sí, estoy hablando de canales laterales).

Estrategia segura "Recordarme" de Paragon Initiative

Almacenamiento:

  1. Genere una cadena de 9 bytes al azar desde random_bytes() (PHP 7.0+ o mediante random_compat ), la base64 lo codifica a 12. Esto se utilizará para búsquedas en bases de datos.
  2. Genere otra cadena aleatoria, preferiblemente de al menos 18 bytes de longitud, y una vez más, codifique en base64 (a 24+). Esto se utilizará realmente para la autenticación.
  3. Almacene $lookup y hash('sha256, $validator) en la base de datos; por supuesto asociado con una cuenta de usuario específica.
  4. Almacene $lookup . $validator en la cookie HTTP del usuario (por ejemplo, rememberme ).

Validación (Inicio de sesión automático):

  1. Divida la cookie en $lookup y $validator .
  2. Realizar una búsqueda en la base de datos basada en $lookup ; está bien si hay un canal lateral de sincronización aquí.
  3. Marque hash_equals($row['hashedValdator'], hash('sha256', $validator)) .
  4. Si el paso 3 devuelve TRUE , asocie la sesión actual con la cuenta de usuario adecuada.

Análisis de seguridad:

  • ¿Qué canales laterales se mitigan?
    Lo más significativo es que mitiga el impacto de la sincronización de las fugas de información en la operación de comparación de cadenas utilizada en la búsqueda de la base de datos.

    Si implementó una autenticación de token aleatoria ingenua, un atacante podría enviar muchas solicitudes hasta que encuentren un token de autenticación válido para un usuario. (Probablemente no podrían seleccionar a qué víctima se están haciendo pasar por la personificación).

  • ¿Qué sucede si un atacante puede filtrar la tabla de la base de datos de autenticación a largo plazo?
    Almacenamos un hash SHA256 del $validator en la base de datos, pero el texto plano para el hash se almacena en la cookie. Dado que la entrada es un alto valor de entropía, es poco probable que la búsqueda de fuerza bruta produzca resultados. (Esto también mitiga la necesidad de, por ejemplo, bcrypt.)

Esta estrategia se implementa en Gatekeeper .

    
respondido por el Scott Arciszewski 01.01.2016 - 08:57
fuente
5

Esa es una pregunta interesante. Comenzaré diciendo que no estoy seguro de que se pueda hacer sin un poco de debilitamiento de la seguridad de la aplicación, pero luego, dependiendo del sitio que se considere que vale la pena el intercambio.

Así que un enfoque podría ser

La base de datos de estado de la sesión deberá registrar la hora en que se establece un token y la duración en que debe recordarse para poder comparar el token presentado.

Cuando el usuario inicia sesión en la aplicación, tiene una casilla de verificación que le permite permanecer conectado (idealmente con un intervalo de períodos de tiempo para que el usuario seleccione)

Cuando se establece el token de sesión, ese período de tiempo se utiliza como la expiración de la cookie. En visitas posteriores, la cookie se presentará a la aplicación y el servidor deberá verificar si sigue siendo válida (es decir, no se ha afectado el período de caducidad de la función Recordarme). Si el token sigue siendo válido, el usuario se trata como autenticado, de lo contrario, el token se borra y el usuario se redirige a la pantalla de inicio de sesión.

Problemas con este enfoque. Los navegadores compartidos significarían que el acceso no autorizado es posible.

También cualquier persona que pueda obtener acceso a la cookie (ya sea a través de una vulnerabilidad en el sitio, un problema del navegador o de malware plantado en la máquina) podrá obtener acceso no autorizado al sitio. Una sugerencia común para mitigar esto es tratar de vincular la cookie a una dirección IP de origen (encriptada o almacenada en el servidor, por supuesto) que se verifica cuando el usuario presenta la cookie, sin embargo, esto causa problemas en grandes entornos corporativos a los que un usuario puede acudir. desde una serie de direcciones IP, y también puede ser susceptible de falsificación.

    
respondido por el Rоry McCune 11.11.2010 - 23:52
fuente
4

No tiene que depender del navegador para eliminar la cookie, tiene el sitio para verificar la fecha de caducidad de la cookie.

De hecho, para que esto sea seguro, diría que probablemente sea lo que tendrá que hacer de todos modos, porque desearía establecer la fecha de caducidad como parte del valor de la cookie y cifrarla en lugar de Confíe en la propiedad de caducidad de texto sin formato de la cookie.

Y realmente querrá marcar la cookie como segura y usar una cookie secundaria durante una sesión individual, o proteger la sesión completa (no solo el proceso de inicio de sesión) con SSL para evitar que la cookie sea robada fuera del cable y utilizado por una parte no autorizada.

    
respondido por el Xander 11.11.2010 - 23:53
fuente
0

Este artículo describe un enfoque que defiende contra el robo de cookies y la identificación de identificaciones de sesión:

  • Una cookie "recordarme" consiste en la ID de usuario, un token (número aleatorio grande) y un token de secuencia (otro número aleatorio grande).
  • Cuando un usuario presenta la cookie, se busca en la base de datos estos tres datos.
    • Si se encuentra, el token de secuencia se regenera, se almacena en la base de datos y se envía al usuario
    • Si solo se encuentran el nombre de usuario y el token, se presume que alguien más ha robado la cookie porque el token de secuencia ya estaba en uso. El sistema puede avisar al usuario y / o eliminar todos los tokens almacenados de este usuario de la base de datos.

Como medida de seguridad adicional, se recomienda que las acciones críticas como cambiar los datos de inicio de sesión o pagar las cosas soliciten la contraseña, si el usuario solo se autenticó con la cookie "recordarme".

La tabla de base de datos que contiene el ID de usuario y los tokens también contiene la fecha de caducidad de los tokens. También podría contener el agente de usuario y la dirección IP, por lo que un atacante también tiene que replicarlos. Todos los tokens solo deben almacenarse como hashes porque básicamente funcionan como contraseñas y permitirían que un atacante, que obtuvo una base de datos, inicie sesión.

He creado una implementación de muestra para PHP.

    
respondido por el chiborg 04.01.2013 - 13:55
fuente
-1

Un enfoque común sería utilizar un algoritmo de cifrado fuerte para almacenar una cookie que contenga la siguiente información en la computadora del usuario:

AES ([Fecha de caducidad] + [sal aleatoria] + [Nombre de usuario] + [Contraseña])

Eso permitiría al usuario invalidar la cookie (si estuviera comprometida) simplemente cambiando su contraseña. El cifrado permite que el operador del sitio verifique que no haya sido manipulado (por ejemplo, extendiendo la fecha de caducidad), así como protegiendo la contraseña de texto claro del compromiso. Incluir la contraseña significa que un atacante que obtiene acceso a la clave AES todavía no puede "acuñar" tokens para autenticarse como usuarios arbitrarios.

La desventaja es que el sitio tiene que proteger una clave AES.

Un enfoque alternativo sería simplemente agregar dos campos a su base de datos de usuarios, para un valor de cookie (valor largo / fuerte / generado aleatoriamente) y una fecha de caducidad asociada. Cualquier usuario que presente esa cookie será autenticado, hasta la fecha de caducidad. Solo hay que asegurarse de que, en el lado del servidor, operaciones como cambiar una contraseña eliminen las cookies "recordarme" almacenadas en la base de datos.

Las ventajas de este enfoque son que no hay una clave de cifrado para administrar (o preocuparse por la renovación), y que no hay posibilidad de que la contraseña del usuario se vea comprometida. Las desventajas son que necesita almacenamiento adicional para sus usuarios.

En el lado positivo, este enfoque le permite proporcionar diferentes tokens "recordarme" en diferentes dispositivos (al igual que el Administrador de cuentas de Google), simplemente almacenando los tokens en una tabla separada y permitiendo más de una entrada por usuario. Esto permite hacer un seguimiento del uso de cada uno e invalidarlos individualmente.

    
respondido por el Rogan Dawes 19.11.2010 - 08:21
fuente

Lea otras preguntas en las etiquetas