Pregunta

Mi aplicación web utiliza sesiones para almacenar información sobre el usuario una vez que ha iniciado sesión y para mantener esa información mientras viaja de una página a otra dentro de la aplicación.En esta aplicación específica, estoy almacenando el user_id, first_name y last_name de la persona.

Me gustaría ofrecer una opción "Mantenerme conectado" al iniciar sesión que colocará una cookie en la máquina del usuario durante dos semanas, que reiniciará su sesión con los mismos detalles cuando regrese a la aplicación.

¿Cuál es el mejor enfoque para hacer esto?No quiero almacenar sus user_id en la cookie, ya que parece que eso facilitaría que un usuario intente falsificar la identidad de otro usuario.

¿Fue útil?

Solución

OK, déjame poner esto sin rodeos: si usted está poniendo los datos de usuario, o cualquier derivado de los datos del usuario en una cookie para este fin, que está haciendo algo mal.

. Lo dije. Ahora podemos pasar a la respuesta real.

¿Qué hay de malo en hash datos de usuario, usted pregunta? Bueno, todo se reduce a la superficie de exposición y la seguridad por oscuridad.

Imagínese por un momento que eres un atacante. Usted ve una cookie criptográfico establecido para el recuerdo-me en su sesión. Es 32 caracteres de ancho. Caramba. Eso puede ser un MD5 ...

Imaginemos también por un segundo que conocen el algoritmo que usa. Por ejemplo:

md5(salt+username+ip+salt)

Ahora, todo lo que un atacante tiene que hacer es la fuerza bruta "sal" (que en realidad no es una sal, pero más sobre esto más adelante), y ahora se puede generar todas las señales falsas que quiera con cualquier nombre de usuario para su ¡Dirección IP! Pero fuerza bruta una sal es difícil, ¿verdad? Absolutamente. Sin embargo, las GPU de hoy en día son muy buenos en eso. Y a menos que utilice la suficiente aleatoriedad en ella (que sea lo suficientemente grande), que va a caer rápidamente, y con él las llaves de su castillo.

En resumen, lo único que protege que es la sal, que no es realmente que protege tanto como usted piensa.

pero espera!

Todo eso se basaba que el atacante conoce el algoritmo! Si es secreta y confuso, entonces estás seguro, ¿verdad? MAL . Esa línea de pensamiento tiene un nombre:. seguridad por oscuridad , que deben nunca confiar en ella

La mejor manera

La mejor manera es no dejar nunca que la información de un usuario deje el servidor, a excepción de la ID.

Cuando el usuario inicia una sesión, generar un token aleatorio grande (128 a 256 bits). Añade que para una tabla de base de datos que mapea el token al identificador de usuario, y luego enviarlo al cliente en la cookie.

¿Qué pasa si el atacante adivina el testigo aleatorio de otro usuario?

Bueno, vamos a hacer algunos cálculos aquí. Estamos generando una muestra aleatoria de 128 bits. Eso significa que hay:

possibilities = 2^128
possibilities = 3.4 * 10^38

Ahora, para mostrar cómo absurdamente grande que el número es, imaginemos cada servidor en Internet (digamos 50 millones en la actualidad) tratando de fuerza bruta ese número a un ritmo de mil millones por segundo cada una. En realidad sus servidores se fundirían en virtud de dicha carga, pero vamos a jugar esto.

guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000

Así que 50 mil billones de conjeturas por segundo. ¡Eso es rápido! ¿Verdad?

time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000

Así que 6.8 trillones segundos ...

Vamos a tratar de lograr que a los números más amigables.

215,626,585,489,599 years

O aún mejor:

47917 times the age of the universe

Sí, eso es 47917 veces la edad del universo ...

Básicamente, no va a ser roto.

Para resumir:

El mejor enfoque que recomiendo es la de almacenar la cookie con tres partes.

function onLogin($user) {
    $token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
    storeTokenForUser($user, $token);
    $cookie = $user . ':' . $token;
    $mac = hash_hmac('sha256', $cookie, SECRET_KEY);
    $cookie .= ':' . $mac;
    setcookie('rememberme', $cookie);
}

A continuación, para validar:

function rememberMe() {
    $cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
    if ($cookie) {
        list ($user, $token, $mac) = explode(':', $cookie);
        if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
            return false;
        }
        $usertoken = fetchTokenByUserName($user);
        if (hash_equals($usertoken, $token)) {
            logUserIn($user);
        }
    }
}

Nota: No utilice la ficha o combinación de usuario y una señal para buscar un registro en su base de datos. Siempre asegúrese de buscar un registro basado en el usuario y el uso de una función de comparación de tiempo de fallos para comparar el token descabellada después. Más sobre la sincronización ataques .

Ahora, es muy importante que el SECRET_KEY sea un secreto criptográfico (generada por algo así como /dev/urandom y / o derivado de una entrada de alta entropía). También, GenerateRandomToken() necesita ser una fuente aleatoria fuerte (mt_rand() no es suficiente casi fuerte. Utilizar una biblioteca, como RandomLib o random_compat o mcrypt_create_iv() con DEV_URANDOM) ...

El hash_equals() es prevenir ataques puntuales . Si utiliza una versión de PHP a continuación PHP 5.6 no es compatible con la función hash_equals() . En este caso se puede sustituir hash_equals() con la función timingSafeCompare:

/**
 * A timing safe equals comparison
 *
 * To prevent leaking length information, it is important
 * that user input is always used as the second parameter.
 *
 * @param string $safe The internal (safe) value to be checked
 * @param string $user The user submitted (unsafe) value
 *
 * @return boolean True if the two strings are identical.
 */
function timingSafeCompare($safe, $user) {
    if (function_exists('hash_equals')) {
        return hash_equals($safe, $user); // PHP 5.6
    }
    // Prevent issues if string length is 0
    $safe .= chr(0);
    $user .= chr(0);

    // mbstring.func_overload can make strlen() return invalid numbers
    // when operating on raw binary strings; force an 8bit charset here:
    if (function_exists('mb_strlen')) {
        $safeLen = mb_strlen($safe, '8bit');
        $userLen = mb_strlen($user, '8bit');
    } else {
        $safeLen = strlen($safe);
        $userLen = strlen($user);
    }

    // Set the result to the difference between the lengths
    $result = $safeLen - $userLen;

    // Note that we ALWAYS iterate over the user-supplied length
    // This is to prevent leaking length information
    for ($i = 0; $i < $userLen; $i++) {
        // Using % here is a trick to prevent notices
        // It's safe, since if the lengths are different
        // $result is already non-0
        $result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
    }

    // They are only identical strings if $result is exactly 0...
    return $result === 0;
}

Otros consejos

  

Aviso de seguridad : Basar la cookie de un hash MD5 de los datos determinista es una mala idea; que es mejor utilizar un contador aleatorio derivado de un CSPRNG. Ver de ircmaxell respuesta a esta pregunta de un enfoque más seguro.

Por lo general hago algo como esto:

  1. El usuario inicia sesión con 'no cerrar sesión'
  2. Crear sesión
  3. Crea una cookie llamada algo que contenga: md5 (sal + nombre de usuario + ip + sal) y una galleta llamada somethingelse contiene id
  4. galletas tienda en la base de datos
  5. El usuario hace cosas y hojas ----
  6. Devuelve al usuario, comprobar para galletas somethingelse, si es que existe, reciben el viejo hash a partir de la base de datos para ese usuario, verificación del contenido de fósforo ALGO cookie con el hash a partir de la base de datos, que también debe coincidir con un hash calculado de nuevo (para el ip) así: cookieHash == databaseHash == md5 (sal + nombre de usuario + ip + sal), si lo hacen, Goto 2, si no lo hacen Goto 1

¡Por supuesto se pueden utilizar diferentes nombres para galletas, etc. También se puede cambiar el contenido de la cookie un poco, sólo asegúrese de que no es creado fácilmente. Por ejemplo, puede crear también un user_salt cuando se crea el usuario y también poner esto en la cookie.

También se puede utilizar en lugar de MD5 SHA1 (o casi cualquier algoritmo)

Introducción

Tu título “Mantenerme conectado”: ​​el mejor enfoque Me resulta difícil saber por dónde empezar porque si busca el mejor enfoque, debería considerar lo siguiente:

  • Identificación
  • Seguridad

Galletas

Las cookies son vulnerables. Entre las vulnerabilidades comunes de robo de cookies de los navegadores y los ataques de secuencias de comandos entre sitios, debemos aceptar que las cookies no son seguras.Para ayudar a mejorar la seguridad debe tener en cuenta que php setcookies tiene funciones adicionales como

booleano establecer galleta ( cadena $nombre [, cadena $valor [, int $expire = 0 [, cadena $ruta [, cadena $dominio [, bool $seguro = falso [, booleano $httpsolo = falso ]]]]]] )

  • seguro (usando conexión HTTPS)
  • httponly (Reducir el robo de identidad mediante ataques XSS)

Definiciones

  • Token (cadena aleatoria impredecible de n longitud, por ejemplo./dev/urandom)
  • Referencia (cadena aleatoria impredecible de n longitud, por ejemplo./dev/urandom)
  • Firma (Genere un valor hash con clave utilizando el método HMAC)

Enfoque sencillo

Una solución sencilla sería:

  • El usuario ha iniciado sesión con Recordarme
  • Cookie de inicio de sesión emitida con token y firma
  • Cuando regresa, se verifica la firma.
  • Si la firma está bien...luego se busca el nombre de usuario y el token en la base de datos
  • si no es valido..volver a la página de inicio de sesión
  • Si es válido iniciar sesión automáticamente

El estudio de caso anterior resume todos los ejemplos dados en esta página, pero su desventaja es que

  • No hay forma de saber si las cookies fueron robadas.
  • El atacante puede acceder a operaciones confidenciales, como cambio de contraseña o datos como información personal y de horneado, etc.
  • La cookie comprometida seguirá siendo válida durante la vida útil de la cookie.

Mejor solución

Una mejor solución sería

  • El usuario ha iniciado sesión y Recordarme está seleccionado
  • Generar token y firma y almacenar en cookie
  • Los tokens son aleatorios y solo son válidos para autenticación única.
  • Los tokens se reemplazan en cada visita al sitio.
  • Cuando un usuario no registrado visita el sitio, se verifican la firma, el token y el nombre de usuario.
  • El inicio de sesión Recuérdame debe tener acceso limitado y no permitir la modificación de contraseña, información personal, etc.

Código de ejemplo

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

Clase usada

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

Pruebas en Firefox y Chrome

enter image description here

Ventaja

  • Mejor seguridad
  • Acceso limitado para atacante
  • Cuando se roba una cookie, solo es válida para un acceso único
  • La próxima vez que el usuario original acceda al sitio, podrá detectar y notificar automáticamente al usuario sobre el robo.

Desventaja

  • No admite conexión persistente a través de múltiples navegadores (móvil y web)
  • La cookie aún puede ser robada porque el usuario solo recibe la notificación después del siguiente inicio de sesión.

Arreglo rapido

  • Introducción de sistema de aprobación para cada sistema que debe tener conexión persistente.
  • Utilice múltiples cookies para la autenticación

Enfoque de cookies múltiples

Cuando un atacante está a punto de robar cookies, céntrelo únicamente en un sitio web o dominio en particular, por ejemplo. ejemplo.com

Pero realmente puedes autenticar a un usuario de 2 dominios diferentes (ejemplo.com & sitiofakeaddsite.com) y hacer que parezca "Cookie de anuncio"

  • Usuario que inició sesión ejemplo.com con recordarme
  • Almacenar nombre de usuario, token y referencia en cookie
  • Almacenar nombre de usuario, token, referencia en la base de datos, por ejemplo.Memcache
  • Envíe la identificación de referencia a través de get e iframe a sitiofakeaddsite.com
  • fakeaddsite.com utiliza la referencia para recuperar el usuario y el token de la base de datos
  • fakeaddsite.com almacena la firma
  • Cuando un usuario regresa, busca información de firma con iframe de fakeaddsite.com
  • Combina los datos y haz la validación.
  • .....ya sabes el resto

Algunas personas podrían preguntarse ¿cómo se pueden utilizar 2 cookies diferentes?Bueno, es posible, imagina example.com = localhost y fakeaddsite.com = 192.168.1.120.Si inspeccionas las cookies se vería así

enter image description here

De la imagen de arriba

  • El sitio visitado actualmente es localhost
  • También contiene cookies configuradas desde 192.168.1.120

192.168.1.120

  • Solo acepta definido HTTP_REFERER
  • Sólo acepta conexión desde especificado REMOTE_ADDR
  • Sin JavaScript, sin contenido, pero no consiste más que en firmar información y agregarla o recuperarla de la cookie

Ventaja

  • El 99% de las veces has engañado al atacante.
  • Puedes bloquear fácilmente la cuenta en el primer intento del atacante.
  • El ataque se puede prevenir incluso antes del siguiente inicio de sesión, al igual que los otros métodos.

Desventaja

  • Solicitud múltiple al servidor solo para un único inicio de sesión

Mejora

  • Uso finalizado uso de iframe ajax

Hay dos artículos muy interesantes, he encontrado durante la búsqueda de una solución perfecta para el "recordar-me" -problema:

Le pregunté a un ángulo de esta cuestión aquí , y las respuestas le llevará a todos los eslabones de tiempo de espera de cookie basadas en tokens que necesita.

Básicamente, no almacena el ID de usuario en la cookie. Almacenar una muestra de una sola vez (enorme cadena), que el usuario utiliza para recoger a su antigua sesión de inicio de sesión. A continuación, para que sea realmente seguro, de pedir una contraseña para operaciones pesadas (como cambiar la contraseña en sí).

Yo recomendaría el enfoque mencionado por Stefan (es decir, seguir las directrices en Improved persistente de sesión de cookies Mejor Práctica ) y también recomienda que se asegure de que las cookies están HttpOnly las cookies lo que no son accesibles para, potencialmente malicioso, JavaScript.

Generar un hash, tal vez con un secreto que sólo usted conoce, a continuación, lo almacena en su base de datos para que pueda ser asociado con el usuario. Debería funcionar bastante bien.

Hilo antiguo, pero sigue siendo una preocupación válida.Noté algunas buenas respuestas sobre seguridad y cómo evitar el uso de "seguridad a través de la oscuridad", pero los métodos técnicos reales proporcionados no fueron suficientes en mi opinión.Cosas que debo decir antes de contribuir con mi método:

  • NUNCA almacene una contraseña en texto claro... ¡NUNCA!
  • NUNCA almacene la contraseña hash de un usuario en más de una ubicación en su base de datos.El backend de su servidor siempre es capaz de extraer la contraseña hash de la tabla de usuarios.No es más eficiente almacenar datos redundantes en lugar de transacciones de base de datos adicionales, sino lo contrario.
  • Los ID de sesión deben ser únicos, de modo que no puedan haber dos usuarios. alguna vez compartir una identificación, de ahí el propósito de una identificación (¿podría alguna vez el número de identificación de su licencia de conducir coincidir con el de otra persona?No.) Esto genera una combinación única de dos piezas, basada en 2 cadenas únicas.Su tabla de Sesiones debe usar el ID como PK.Para permitir que se confíe en varios dispositivos para el inicio de sesión automático, utilice otra tabla para dispositivos confiables que contenga la lista de todos los dispositivos validados (consulte mi ejemplo a continuación) y se asigne utilizando el nombre de usuario.
  • No tiene ningún propósito convertir datos conocidos en una cookie; la cookie se puede copiar.Lo que buscamos es un dispositivo de usuario compatible que proporcione información auténtica que no se puede obtener sin que un atacante comprometa la máquina del usuario (nuevamente, vea mi ejemplo).Esto significaría, sin embargo, que un usuario legítimo que prohíba la información estática de su máquina (es decir,La dirección MAC, el nombre de host del dispositivo, el agente de usuario si está restringido por el navegador, etc.) permanezcan consistentes (o lo falsifiquen en primer lugar) no podrán utilizar esta función.Pero si esto le preocupa, considere el hecho de que está ofreciendo el inicio de sesión automático a los usuarios que identificarse de forma única, por lo que si se niegan a ser conocidos falsificando su MAC, falsificando su agente de usuario, falsificando/cambiando su nombre de host, escondiéndose detrás de servidores proxy, etc., entonces no son identificables y nunca deben autenticarse para un servicio automático.Si desea esto, debe considerar el acceso con tarjeta inteligente incluido con el software del lado del cliente que establece la identidad del dispositivo que se utiliza.

Dicho todo esto, existen dos formas excelentes de tener el inicio de sesión automático en su sistema.

En primer lugar, la forma fácil y barata de dejarlo todo en manos de otra persona.Si hace que su sitio admita el inicio de sesión con, digamos, su cuenta de Google+, probablemente tenga un botón de Google+ optimizado que iniciará la sesión del usuario si ya ha iniciado sesión en Google (lo hice aquí para responder esta pregunta, como siempre lo hago). iniciado sesión en google).Si desea que el usuario inicie sesión automáticamente si ya inició sesión con un autenticador confiable y compatible, y marcó la casilla para hacerlo, haga que sus scripts del lado del cliente ejecuten el código detrás del botón correspondiente 'iniciar sesión con' antes de cargar , solo asegúrese de que el servidor almacene una identificación única en una tabla de inicio de sesión automático que tenga el nombre de usuario, la identificación de sesión y el autenticador utilizado para el usuario.Dado que estos métodos de inicio de sesión utilizan AJAX, usted está esperando una respuesta de todos modos, y esa respuesta es una respuesta validada o un rechazo.Si obtiene una respuesta validada, úsela normalmente y luego continúe cargando el usuario que inició sesión normalmente.De lo contrario, el inicio de sesión falló, pero no se lo diga al usuario, simplemente continúe como si no hubiera iniciado sesión, lo notarán.Esto es para evitar que un atacante que robó cookies (o las falsificó en un intento de escalar privilegios) se entere de que el usuario inicia sesión automáticamente en el sitio.

Esto es barato y algunos también podrían considerarlo sucio porque intenta validar su posible cuenta ya iniciada en lugares como Google y Facebook, sin siquiera decírselo.Sin embargo, no debe usarse con usuarios que no hayan solicitado iniciar sesión automáticamente en su sitio, y este método en particular es solo para autenticación externa, como con Google+ o FB.

Debido a que se utilizó un autenticador externo para decirle al servidor detrás de escena si un usuario fue validado o no, un atacante no puede obtener nada más que una identificación única, que es inútil por sí sola.Voy a elaborar:

  • El usuario 'joe' visita el sitio por primera vez, el ID de sesión se coloca en la cookie 'sesión'.
  • El usuario 'joe' inicia sesión, aumenta los privilegios, obtiene una nueva ID de sesión y renueva la 'sesión' de cookies.
  • El usuario 'joe' elige iniciar sesión automáticamente usando google+ y obtiene una identificación única en la cookie 'keepmesignedin'.
  • El usuario 'joe' hace que Google lo mantenga conectado, lo que permite que su sitio inicie sesión automáticamente al usuario usando Google en su backend.
  • El atacante intenta sistemáticamente identificaciones únicas para 'keepmesignedin' (esto es conocimiento público entregado a cada usuario) y no inicia sesión en ningún otro lugar;intenta la identificación única dada a 'joe'.
  • El servidor recibe una identificación única para 'joe' y obtiene una coincidencia en la base de datos para una cuenta de Google+.
  • El servidor envía al atacante a la página de inicio de sesión que ejecuta una solicitud AJAX a Google para iniciar sesión.
  • El servidor de Google recibe una solicitud y utiliza su API para ver que el atacante no ha iniciado sesión actualmente.
  • Google envía una respuesta indicando que actualmente no hay ningún usuario que haya iniciado sesión en esta conexión.
  • La página del atacante recibe respuesta, el script redirige automáticamente a la página de inicio de sesión con un valor POST codificado en la URL.
  • La página de inicio de sesión obtiene el valor POST, envía la cookie para 'keepmesignedin' a un valor vacío y una fecha válida hasta el 1-1-1970 para disuadir un intento automático, lo que hace que el navegador del atacante simplemente elimine la cookie.
  • Al atacante se le proporciona una página de inicio de sesión normal por primera vez.

Pase lo que pase, incluso si un atacante utiliza una identificación que no existe, el intento debería fallar en todos los intentos excepto cuando se recibe una respuesta validada.

Este método puede y debe usarse junto con su autenticador interno para aquellos que inician sesión en su sitio utilizando un autenticador externo.

=========

Ahora, para su propio sistema de autenticación que puede iniciar sesión automáticamente, así es como lo hago:

DB tiene algunas tablas:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

Tenga en cuenta que el nombre de usuario puede tener 255 caracteres.Tengo el programa de mi servidor que limita los nombres de usuario en mi sistema a 32 caracteres, pero los autenticadores externos pueden tener nombres de usuario con su @dominio.tld más grandes que eso, por lo que solo admito la longitud máxima de una dirección de correo electrónico para una máxima compatibilidad.

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

Tenga en cuenta que no hay ningún campo de usuario en esta tabla, porque el nombre de usuario, cuando inicia sesión, está en los datos de la sesión y el programa no permite datos nulos.El session_id y el session_token se pueden generar usando hashes md5 aleatorios, hashes sha1/128/256, marcas de fecha y hora con cadenas aleatorias agregadas y luego procesadas, o lo que desee, pero la entropía de su salida debe permanecer tan alta como sea tolerable. mitigue los ataques de fuerza bruta incluso para que no despeguen, y todos los hashes generados por su clase de sesión deben verificarse para ver si coinciden en la tabla de sesiones antes de intentar agregarlos.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code

Las direcciones MAC, por su naturaleza, se supone que son ÚNICAS, por lo tanto tiene sentido que cada entrada tenga un valor único.Los nombres de host, por otro lado, podrían duplicarse legítimamente en redes separadas.¿Cuántas personas utilizan "Home-PC" como uno de los nombres de sus computadoras?El servidor backend toma el nombre de usuario de los datos de la sesión, por lo que manipularlo es imposible.En cuanto al token, se debe utilizar el mismo método para generar tokens de sesión para páginas para generar tokens en cookies para el inicio de sesión automático del usuario.Por último, se agrega el código de fecha y hora para cuando el usuario necesite revalidar sus credenciales.Actualice esta fecha y hora en el inicio de sesión del usuario y manténgala dentro de unos pocos días, o fuerce su caducidad independientemente del último inicio de sesión y manténgala solo durante aproximadamente un mes, lo que dicte su diseño.

Esto evita que alguien falsifique sistemáticamente la MAC y el nombre de host de un usuario que sabe que inicia sesión automáticamente. NUNCA hacer que el usuario guarde una cookie con su contraseña, texto sin cifrar o de otro modo.Haga que el token se regenere en cada navegación de página, tal como lo haría con el token de sesión.Esto reduce enormemente la probabilidad de que un atacante obtenga una cookie token válida y la utilice para iniciar sesión.Algunas personas intentarán decir que un atacante podría robar las cookies de la víctima y realizar un ataque de repetición de sesión para iniciar sesión.Si un atacante pudiera robar las cookies (lo cual es posible), ciertamente habría comprometido todo el dispositivo, lo que significa que podría usar el dispositivo para iniciar sesión de todos modos, lo que anula por completo el propósito de robar cookies.Siempre que su sitio funcione a través de HTTPS (lo que debería hacer cuando se trata de contraseñas, números CC u otros sistemas de inicio de sesión), le ha brindado al usuario toda la protección posible dentro de un navegador.

Una cosa a tener en cuenta:Los datos de la sesión no deberían caducar si utiliza el inicio de sesión automático.Puede expirar la capacidad de continuar la sesión falsamente, pero la validación en el sistema debería reanudar los datos de la sesión si se trata de datos persistentes que se espera que continúen entre sesiones.Si desea datos de sesión persistentes Y no persistentes, use otra tabla para datos de sesión persistentes con el nombre de usuario como PK y haga que el servidor los recupere como lo haría con los datos de sesión normales, solo use otra variable.

Una vez que se haya logrado iniciar sesión de esta manera, el servidor aún debería validar la sesión.Aquí es donde puedes codificar las expectativas para sistemas robados o comprometidos;Los patrones y otros resultados esperados de los inicios de sesión en los datos de sesión a menudo pueden llevar a conclusiones de que un sistema fue secuestrado o que se falsificaron cookies para obtener acceso.Aquí es donde su ISS Tech puede establecer reglas que desencadenarían el bloqueo de la cuenta o la eliminación automática de un usuario del sistema de inicio de sesión automático, manteniendo a los atacantes fuera el tiempo suficiente para que el usuario determine cómo tuvo éxito el atacante y cómo aislarlos.

Como nota final, asegúrese de que cualquier intento de recuperación, cambio de contraseña o falla de inicio de sesión que supere el umbral provoque la desactivación del inicio de sesión automático hasta que el usuario valide correctamente y reconozca que esto ha ocurrido.

Pido disculpas si alguien esperaba que se proporcionara un código en mi respuesta, eso no sucederá aquí.Diré que uso PHP, jQuery y AJAX para ejecutar mis sitios, y NUNCA uso Windows como servidor...alguna vez.

Mi solución es así. No es 100% a prueba de balas, pero creo que va a ahorrar para la mayoría de los casos.

Cuando el usuario ha iniciado sesión en crear con éxito una cadena con esta información:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

Cifrar $data, establecer el tipo de HttpOnly y establecer cookies.

Cuando el usuario vuelve a su sitio, hacer estos pasos:

  1. Obtener datos de las cookies. Quitar los caracteres peligrosos dentro de la galleta. Explotar con carácter :.
  2. Comprobar la validez. Si cookie es más de X días y luego redirigir a la página de acceso de usuario.
  3. Si cookie no es viejo; Recibir las últimas tiempo de cambio de contraseña de base de datos. Si se cambia la contraseña de inicio de sesión de usuario después de la última redirección del usuario a la página de acceso.
  4. Si no pase fue cambiado recientemente; Obtener agente navegador actual del usuario. Comprobar si (== currentUserAgentHash cookieUserAgentHash). Si los agentes son iguales ir al siguiente paso, de lo redirigirá a la página de acceso.
  5. Si todos los pasos superado con éxito autorizan nombre de usuario.

Si signouts usuario, eliminar esta cookie. Crear nueva cookie si el usuario vuelve a los inicios de sesión.

No entiendo el concepto de almacenar cosas cifrada en una cookie cuando es la versión cifrada de la misma que tiene que hacer su piratería. Si me falta algo, por favor comentar.

Estoy pensando en tomar este enfoque de 'Remember Me'. Si puede ver cualquier problema, por favor comentar.

  1. Crea una tabla para almacenar "Remember Me" en los datos -. Separar a la tabla de usuario para que pueda acceder desde múltiples dispositivos

  2. El inicio de sesión correcto (con Recordarme marcado):

    a) Generar una cadena aleatoria única para ser usado como el ID de usuario en esta máquina: bigUserID

    b) Generar una cadena aleatoria único: bigKey

    c) Se almacena una cookie: bigUserID: bigKey

    d) En la tabla de "Remember Me", añadir un registro con: ID de usuario, dirección IP, bigUserID, bigKey

  3. Si al tratar de acceder a algo que requiere entrada:

    a) Compruebe si la cookie y la búsqueda de bigUserID y bigKey con una dirección IP a juego

    b) Si lo encuentra, Entrar en la persona, sino establecer un indicador en la tabla de usuario "Inicio de sesión suave" de modo que para cualquier operación peligrosas, puede solicitar para un inicio de sesión completa.

  4. El cierre de sesión, Mark todos los "Recordarme" registros para ese usuario mientras que expiró.

Las únicas vulnerabilidades que puedo ver es;

  • que podría hacerse con el portátil de alguien y falsificar su dirección IP con la cookie.
  • que podría suplantar una dirección IP diferente cada vez y supongo que todo el asunto -, pero con dos grandes para que coincida con la cadena, que sería ... haciendo un cálculo similar al anterior ... no tengo ni idea ... enormes probabilidades ?

He leído todas las respuestas y todavía resultaba difícil extraer lo que tenía que hacer. Si una imagen vale más palabras 1k espero que esto ayude a otros implementan un almacenamiento persistente seguro, basado en Mejora persistente de sesión de cookies de Buenas Prácticas de Barry Jaspan

introducir descripción de la imagen aquí

Si tiene preguntas, comentarios o sugerencias, voy a tratar de actualizar el diagrama para reflejar el novato tratando de implementar un inicio de sesión permanente seguro.

La implementación de un "No cerrar sesión" característica significa que es necesario definir exactamente lo que eso significa para el usuario. En el caso más simple, me gustaría utilizar en el sentido de que la sesión tiene un tiempo de espera mucho más tiempo: 2 días (por ejemplo) en lugar de 2 horas. Para ello, tendrá que tener su propio almacenamiento de sesión, probablemente en una base de datos, lo que puede establecer tiempos de encargo de caducidad correspondientes a los datos de la sesión. Luego hay que asegurarse de que se crea una cookie que se pegará alrededor de unos pocos días (o más), en lugar de expirar cuando se cierre el navegador.

Puedo oírte preguntar "¿por 2 días ¿Por qué no 2 semanas?". Esto es porque el uso de una sesión en PHP empujará automáticamente la expiración de vuelta. Esto se debe a la expiración de un período de sesiones en PHP es en realidad un tiempo de inactividad.

Ahora, habiendo dicho eso, probablemente me gustaría poner en práctica un valor de tiempo de espera más duro que almaceno en la sesión, y salir a las 2 semanas más o menos, y añadir código para ver eso y para invalidar la fuerza a la sesión. O al menos para registrar a cabo. Esto significa que se le pedirá al usuario para iniciar sesión periódicamente. Yahoo! Hace esto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top