Se nosso site vê que o Facebook assinado no usuário tem ID de usuário 678678678 no cookie, como sabemos que esse cookie não é falsificado?

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

  •  25-09-2019
  •  | 
  •  

Pergunta

Acho que se fizermos chamadas para o Facebook usando a API REST ou GRAFT, saberemos se for falso, porque voltará dizendo a sessão falsa / auth_token / access_token. Mas e se estivermos mostrando nossas próprias informações de banco de dados, como a "Lista de produtos mais preferida do usuário, não ligamos para o Facebook, mas mostramos os dados do nosso banco de dados. Como sabemos que é realmente o usuário, não alguém fingindo o biscoito?

Foi útil?

Solução

Quando você lê um cookie com o Facebook, ele contém um valor chamado 'sig'. Com esse valor, os outros valores de cookies e seu aplicativo segredo você haviam o conteúdo do cookie e o validam contra a SIG. Se eles corresponderem, o cookie será válido. Você pode confiar nesse resultado, porque somente você e o Facebook têm acesso ao segredo do aplicativo. Aqui está o exemplo de como o PHP SDK do Facebook faz isso. Qualquer respeitável SDK do Facebook fará tudo isso por você 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;
  }

Aqui está a mesma coisa em 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();
    }

Outras dicas

A única coisa em que você pode confiar é session_key Para API de REST antigo e access_token Para API do gráfico. Depois de obtê -lo, passe -o para um lado do servidor com sua solicitação de retrabalho de dados. No lado do servidor, ligue para a API do Facebook e obtenha o UserID atual. Depois de obter o UserID, você pode armazená -lo em uma sessão e usá -lo mais tarde.

Não guarde -o em um biscoito. Coloque -o em uma variável de sessão, assim você tem controle

Não coloque um ID de usuário em um cookie. O cookie da sessão deve ser apenas um número aleatório que mapeia um registro no banco de dados da sessão do servidor. Quaisquer dados associados a essa sessão são armazenados apenas no lado do servidor.

Dessa forma, para fingir uma sessão, um invasor teria que adivinhar um número aleatório que realmente em uso naquele momento. Dado que existem muitos números e sessões aleatórios expiram, isso é quase impossível.

Existem algumas abordagens aqui.

Ineficiente: sempre que você executar uma operação autenticada, pegue o cookie FB e use os dados para fazer uma chamada de API dummy para ver que o token de acesso é válido e corresponde ao usuário (ou seja, Grab /me? Fields = ID).

Mais eficiente: a primeira vez que você vê um cookie do FB para um usuário, armazena que cookie em uma sessão do lado do servidor para o usuário (com um ID de sessão suficientemente difícil para adivinhar passou para o cliente em um cookie).

Outra abordagem, e não requer estado de sessão do servidor: a primeira vez que você vê um cookie FB para um usuário, hmac o cookie usando um segredo que apenas seus servidores têm e armazenar esse hash resultante em um cookie. Então você pode verificar se há um hash válido do cookie do FB e, se sim, confia nele. Caso contrário, você volta à validação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top