Si nuestro sitio web ve que el usuario de Facebook tiene ID de usuario 678678678 en la cookie, ¿cómo sabemos que esta cookie no es falsificada?

StackOverflow https://stackoverflow.com/questions/4002616

  •  25-09-2019
  •  | 
  •  

Pregunta

Creo que si hacemos llamadas a Facebook usando API REST o Graph, sabremos si es falso porque volverá diciendo una sesión falsa / Auth_Token / Access_Token. Pero, ¿qué pasa si mostramos nuestra propia información de DB, como la "lista de productos más preferida" del usuario, entonces no hacemos ninguna llamada a Facebook sino que mostramos los datos de nuestro DB? ¿Cómo sabemos que es realmente el usuario, no alguien fingiendo la galleta?

¿Fue útil?

Solución

Cuando lees una cookie con Facebook, contiene un valor llamado 'Sig'. Con este valor, los otros valores de las cookies y su aplicación secretan que hash el contenido de la cookie y lo validas contra el sig. Si coinciden, entonces la cookie es válida. Puede confiar en este resultado porque solo usted y Facebook tienen acceso al secreto de la aplicación. Aquí está el ejemplo de cómo lo hace el SDK PHP de Facebook. Cualquier SDK de Facebook respetable hará todo esto por usted internamente.

/**
   * Validates a session_version=3 style session object.
   *
   * @param Array $session the session object
   * @return Array the session object if it validates, null otherwise
   */
  protected function validateSessionObject($session) {
    // make sure some essential fields exist
    if (is_array($session) &&
        isset($session['uid']) &&
        isset($session['access_token']) &&
        isset($session['sig'])) {
      // validate the signature
      $session_without_sig = $session;
      unset($session_without_sig['sig']);
      $expected_sig = self::generateSignature(
        $session_without_sig,
        $this->getApiSecret()
      );
      if ($session['sig'] != $expected_sig) {
        self::errorLog('Got invalid session signature in cookie.');
        $session = null;
      }
      // check expiry time
    } else {
      $session = null;
    }
    return $session;
  }

Aquí está lo mismo en C# (Facebook C# SDK):

 /// <summary>
    /// Validates a session_version=3 style session object.
    /// </summary>
    /// <param name="session">The session to validate.</param>
    protected override void ValidateSessionObject(FacebookSession session)
    {
        if (session == null)
        {
            return;
        }

        var signature = this.GenerateSignature(session);
        if (session.Signature == signature.ToString())
        {
            return;
        }

        session = null;
    }

    /// <summary>
    /// Generates a MD5 signature for the facebook session.
    /// </summary>
    /// <param name="session">The session to generate a signature.</param>
    /// <returns>An MD5 signature.</returns>
    /// <exception cref="System.ArgumentNullException">If the session is null.</exception>
    /// <exception cref="System.InvalidOperationException">If there is a problem generating the hash.</exception>
    protected override string GenerateSignature(FacebookSession session)
    {
        var args = session.Dictionary;
        StringBuilder payload = new StringBuilder();
        var parts = (from a in args
                     orderby a.Key
                     where a.Key != "sig"
                     select string.Format(CultureInfo.InvariantCulture, "{0}={1}", a.Key, a.Value)).ToList();
        parts.ForEach((s) => { payload.Append(s); });
        payload.Append(this.ApiSecret);
        byte[] hash = null;
        using (var md5 = System.Security.Cryptography.MD5CryptoServiceProvider.Create())
        {
            if (md5 != null)
            {
                hash = md5.ComputeHash(Encoding.UTF8.GetBytes(payload.ToString()));
            }
        }

        if (hash == null)
        {
            throw new InvalidOperationException("Hash is not valid.");
        }

        StringBuilder signature = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            signature.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture));
        }

        return signature.ToString();
    }

Otros consejos

Lo único que puedes confiar es session_key para la antigua API de descanso y access_token para la API gráfica. Una vez que lo haya recibido, paséelo a un lado del servidor con su solicitud de Remirval de datos. En el lado del servidor, llame a la API de Facebook y obtenga ID de usuario actual. Una vez que obtenga un ID de usuario, puede almacenarlo en una sesión y usarlo más tarde.

No lo guarde en una galleta. Póntalo en una variable de sesión, de esa manera tienes control

No ponga una identificación de usuario en una cookie. La cookie de sesión debe ser un número aleatorio que se asigna a un registro en su base de datos de sesión del lado del servidor. Cualquier datos asociados a esa sesión solo se almacena del lado del servidor.

De esa manera, para fingir una sesión, un atacante tendría que adivinar un número aleatorio que realmente en uso en ese momento. Dado que hay muchos números aleatorios y sesiones, eso es casi imposible.

Hay algunos enfoques aquí.

Ineficiente: cada vez que realiza una operación autenticada, tome la cookie FB y use los datos para hacer una llamada de API ficticia para ver que el token de acceso es válido y coincide con el usuario (es decir, Grab /Me? Fields = id).

Más eficiente: la primera vez que ve una cookie FB para un usuario, guarde esa cookie en una sesión del lado del servidor para el usuario (con una ID de sesión suficientemente dura a sugerencia pasada al cliente en una cookie).

Otro enfoque, y no requiere un estado de sesión del lado del servidor: la primera vez que ve una cookie FB para un usuario, HMAC la cookie que usa un secreto que solo sus servidores tienen y almacena ese hash que resulta en una cookie. Entonces puede verificar si hay un hash válido de la cookie FB, y si es así, confía en él. De lo contrario, vuelves a la validación.

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