Estou desenvolvendo um aplicativo que suporta muitos usuários. O problema é que não consigo descobrir como autenticar o cliente / usuário.
Estou criando um aplicativo como http://quickblox.com/, onde darei credenciais aos meus usuários e eles os usarão para criar N aplicativos nos quais não poderão colocar seu nome de usuário e senha para se autenticar.
Vamos assumir que segue como segue. (Assim como o QuickBlox)
1. O usuário cria uma conta no meu site.
2. O usuário pode criar chaves N API e secretar credenciais. (Para vários aplicativos)
3. O usuário usará essas credenciais em seus aplicativos (Android, iOS, Javascript etc ...) para conversar com minhas APIs REST.
(APIs REST têm acesso de leitura e gravação.)
A minha preocupação?
Os usuários colocam suas credenciais (chave API e chave secreta) nos aplicativos criados, e se alguém obtiver essas chaves e tentar imitar o usuário? (Ao descompilar o APK ou pesquisar diretamente no código JavaScript.
Estou errado em algum lugar?
Estou confuso ao arquitetar esse mecanismo de usuário de três níveis.
Respostas:
Eu tenho desenvolvido APIs REST nos últimos anos. Você está se preocupando demais. Recentemente, outro usuário deste fórum fez uma pergunta, onde estava preocupado em armazenar pontos de extremidade URI em seu código JavaScript do lado do cliente .
As mesmas regras se aplicam a você e ao desenvolvedor JavaScript. Se você permitir que pessoas de fora integrem sua API, ela terá a mesma visibilidade que um site comum e você deve tratá-la da mesma maneira.
Citação da resposta original:
Você deve projetar os tokens de acesso ao aplicativo para permitir apenas operações que você deseja permitir. Você pode ter dois tipos de tokens de acesso:
Mas o que alguém desconstrói o código-fonte, remove os tokens do aplicativo, descobre quais são os pontos de extremidade públicos e abusa do serviço da Web?
A menos que você esteja gerenciando diretamente o desenvolvimento dos aplicativos que consomem sua API, nada realmente proíbe que as pessoas abusem da API da mesma maneira diretamente do aplicativo.
fonte
filtered data
(B) dele . Agora é possível ou existe alguma solução alternativa para impedir que o terceiro usuário roube todos os dados (A + B) do meu usuário . Isso faz sentido?Seu problema não é tanto técnico como comercial.
Digamos que você tenha sua API, que você vende para seus clientes (os desenvolvedores de aplicativos) por uma taxa fixa de £ 100 por ano, acesso ilimitado.
Bem, obviamente, posso comprar seu serviço por 100 libras e vendê-lo para 10 pessoas por US $ 50 cada. Você não quer isso! então você tenta pensar em uma restrição que permita vender sua API sem que ela seja aberta à arbitragem.
Se você apenas restringir o número de aplicativos, um cliente poderá criar um único aplicativo que aceite conexões de outros aplicativos e os repasse.
Se você limitar os usuários, novamente, o cliente poderá ocultar os usuários atrás de sua própria autenticação e parecer ser um único usuário.
O que você precisa fazer é repassar o custo de cada chamada da API para o seu cliente. ou seja, cobrar por chamada da API ou definir uma cota de chamadas por ano.
Isso coloca o mesmo problema de arbitragem em seus clientes. Obriga-os a implementar medidas para impedir que seus usuários roubem suas chaves. Nesse caso, oculte sua API por trás da própria API autenticada pelo usuário.
fonte
Todas as outras respostas parecem sugerir que o problema de armazenar um segredo em um aplicativo em dispositivos de consumo não é solucionável.
Claro que é.
Dois princípios (os detalhes da implementação seguirão):
Dado que, se o cliente fizer uma solicitação ao ponto final de autenticação com credenciais e o servidor autenticar, o servidor poderá gerar um token temporário dinâmico (significado temporário com base no tempo). Esse token deve ser lembrado no cliente e enviado com solicitações subsequentes.
Você precisará de um mecanismo para "atualizar" periodicamente o token, ou seja, obter um novo. Basta criar um terminal REST que permita gerar um novo token a partir de um já existente, para evitar a necessidade de se autenticar novamente de credenciais.
Se você estiver tentando evitar que o usuário final se autentique novamente, essa autenticação poderá ser uma configuração única no aplicativo quando ele for instalado.
Essa solução simplesmente evita a necessidade de armazenar um token estático incorporado no binário do aplicativo. Um token é gerado imediatamente pelo servidor apenas em resposta a uma autenticação bem-sucedida. Para que um usuário mal-intencionado inspecione seu aplicativo e tente obter acesso não autorizado à API, ele ainda precisará se autenticar como qualquer outra pessoa.
fonte
Se você tiver chaves únicas por aplicativo, poderá usá-las apenas durante uma autenticação de conexão inicial, iniciada pelo cliente, após a qual você alterna para um token de autenticação exclusivo por aplicativo rolante.
Seu servidor altera (rola) o token para cada aplicativo cliente de tempos em tempos (periodicamente mais / menos algum atraso aleatório difuso / aleatório, por exemplo). O token rotativo é conhecido apenas pelo servidor e pelo cliente autenticado.
Os novos tokens são devolvidos às respostas regulares. Sempre que a resposta contém um novo token, o aplicativo receptor precisa mudar para usá-lo em solicitações subsequentes.
Sempre que a troca com um cliente ficar fora de sincronia (algum tipo de erro de protocolo), o servidor solicitará a re-autenticação (por meio de uma resposta de erro à próxima solicitação do cliente, ou suportará a resposta válida à solicitação do cliente, por exemplo).
A autenticação inicial iniciada pelos clientes enquanto um token rotativo é usado ativamente deve ser considerada com suspeita - pode muito bem ser uma tentativa de imitação. Eu permitiria apenas se a troca ficasse ociosa por um intervalo maior que o esperado, o que poderia, por exemplo, ser causado por uma interrupção / reinicialização do cliente com uma nova instância que não possui o token de rolagem.
Seria ainda melhor persistir o token no lado do cliente, para que um cliente reiniciado possa continuar de onde seu antecessor saiu - estreitando significativamente a abertura para imitar.
Esse esquema tornaria a imitação pelo menos bastante difícil - o cliente imitador precisaria prever exatamente a janela quando o cliente autorizado parar de enviar solicitações por tempo suficiente para o servidor decidir que não há problema em aceitar uma nova autenticação de cliente com a chave prescrita. Tais solicitações fora da janela permitida podem ser usadas como detecção de tentativas de imitação e, possivelmente, iniciar algumas contramedidas (lista negra de IP, etc.).
fonte
Pelo que sei, o que você mencionou é a única maneira de fazer isso. O aplicativo que armazena a chave é definitivamente um risco, mas existem várias maneiras de contorná-la. Você sempre pode usar o keystore para armazenar a chave, em vez de codificar, forçando assim um login único.
Além disso, considere vincular uma chave a um cliente; assim, se alguém imitar, deverá ter uma camada de segurança para verificar se o cliente, a chave e os agentes do usuário bloqueiam a solicitação imediatamente. Tenha um caso de uso para emitir novamente ou garantir novamente que as chaves não sejam imitadas.
fonte
Se você depende de fornecer tokens de autorização para seus clientes colocarem seus aplicativos, sempre será teoricamente possível para alguém fazer engenharia reversa do aplicativo e extraí-los. Para evitar isso, você precisará de um mecanismo que não exija um segredo no aplicativo cliente. Isso é complicado. Eu posso sugerir algumas opções para você pensar.
Você tem um problema depois de fornecer as credenciais, não tem controle sobre a segurança com que elas são armazenadas. Além disso, se você exigir que o usuário envie as credenciais para você, alguém poderá MITM sua conexão e roubar os tokens diretamente sem se preocupar em fazer engenharia reversa no aplicativo.
Uma maneira de tornar mais difícil extrair seu token de autorização é ofuscá-lo. Isso apenas eleva a fasquia, mas não torna impossível, e para fazer isso, você teria que manter o controle do segredo. Você pode implementar uma biblioteca que contém as informações secretas e é específica para cada cliente. Você pode usar a biblioteca para se comunicar com seus servidores e talvez nem precise informar ao usuário as informações secretas, elas podem ser incorporadas à biblioteca. Isso não resolve o problema de alguém fazer engenharia reversa na sua biblioteca, mas coloca você no controle do nível de ofuscação. Uma desvantagem é que, uma vez que uma pessoa tenha quebrado a ofuscação na biblioteca, ela poderá atacar qualquer biblioteca sua, a menos que você escreva um código que torne cada biblioteca significativamente diferente. Isso introduz seu próprio conjunto de problemas.
Isso pode se afastar um pouco do escopo da sua pergunta, mas está relacionado à segurança do seu token, por isso vou mencioná-lo. Para impedir o roubo trivial do token pela conexão, você provavelmente não deseja enviar o token diretamente; em vez disso, você pode assinar o tráfego usando uma função HMAC. Você pode verificar a validade da mensagem calculando o HMAC da mensagem no servidor e comparando-o com o HMAC enviado do cliente. Você usaria o token como a chave para a função HMAC, para que apenas alguém que conheça o token possa assinar tráfego. Isso é melhor para a segurança do seu token, porque você nunca o envia diretamente para o servidor, para que não possa ser interceptado e roubado diretamente. Para obter mais informações sobre o HMACS, consulte esta pergunta: /security/20129/how-and-when-do-i-use-hmac/20301
Nenhuma solução de segurança é inexpugnável; você precisa decidir quanto vai custar para implementar versus a probabilidade e o custo de ser comprometido.
fonte
Citando a si mesmo:
Agora isso é um pouco contraditório, não é? ;)
Como outros disseram, você não pode. Se um aplicativo usa uma chave de API, pode-se descompilar como você pede para obter a (s) chave (s) e usá-la também.
Além de exigir autenticação adequada adicional do usuário, você só pode limitar o dano:
fonte