Criando uma API para aplicativos móveis - Autenticação e Autorização

189

Visão geral

Estou procurando criar uma API (REST) ​​para meu aplicativo. O objetivo inicial / principal será o consumo por aplicativos móveis (iPhone, Android, Symbian etc.). Estive estudando diferentes mecanismos de autenticação e autorização para APIs baseadas na Web (estudando outras implementações). Eu tenho minha cabeça envolvida na maioria dos conceitos fundamentais, mas ainda estou procurando orientação em algumas áreas. A última coisa que quero fazer é reinventar a roda, mas não estou encontrando soluções padrão que atendam aos meus critérios (no entanto, meus critérios podem ser equivocados, fique à vontade para criticar isso também). Além disso, quero que a API seja a mesma para todas as plataformas / aplicativos que a consomem.

oAuth

Vou seguir em frente e rejeitar minha objeção ao oAuth, pois sei que essa provavelmente será a primeira solução oferecida. Para aplicativos móveis (ou mais especificamente não relacionados à Web), parece errado deixar o aplicativo (acessar um navegador da Web) para autenticação. Além disso, não há como o navegador retornar o retorno de chamada ao aplicativo (especialmente entre plataformas). Conheço alguns aplicativos que fazem isso, mas parece errado e dá uma pausa no aplicativo UX.

Exigências

  1. O usuário insere o nome de usuário / senha no aplicativo.
  2. Toda chamada de API é identificada pelo aplicativo de chamada.
  3. As despesas gerais são reduzidas ao mínimo e o aspecto de autenticação é intuitivo para os desenvolvedores.
  4. O mecanismo é seguro para o usuário final (suas credenciais de logon não são expostas) e também para o desenvolvedor (suas credenciais de aplicativos não são expostas).
  5. Se possível, não exija https (de maneira alguma um requisito rígido).

Meus pensamentos atuais sobre implementação

Um desenvolvedor externo solicitará uma conta da API. Eles receberão um apikey e um sigilo. Toda solicitação exigirá no mínimo três parâmetros.

  • apikey - dado ao desenvolvedor na inscrição
  • timestamp - funciona como um identificador exclusivo para cada mensagem de um determinado apikey
  • hash - um hash do timestamp + o apisecret

O apikey é necessário para identificar o aplicativo que emite a solicitação. O registro de data e hora age de maneira semelhante ao oauth_nonce e evita / mitiga ataques de repetição. O hash garante que a solicitação foi realmente emitida pelo proprietário do apikey fornecido.

Para solicitações autenticadas (feitas em nome de um usuário), ainda estou indeciso entre escolher uma rota access_token ou uma combinação de hash de nome de usuário e senha. De qualquer forma, em algum momento, será necessária uma combinação de nome de usuário / senha. Portanto, quando isso acontecer, um hash de várias informações (apikey, apisecret, timestamp) + a senha será usada. Eu adoraria comentários sobre esse aspecto. Para sua informação, eles teriam que fazer o hash da senha primeiro, já que eu não armazeno as senhas no meu sistema sem o hash.

Conclusão

Para sua informação, este não é um pedido de como criar / estruturar a API em geral, apenas como lidar com a autenticação e autorização somente dentro de um aplicativo.

Perguntas aleatórias sobre pensamentos / bônus

Para APIs que exigem apenas um apikey como parte da solicitação, como você evita que alguém que não seja o proprietário do apikey consiga ver o apikey (desde que foi enviado de forma clara) e faz solicitações excessivas para empurrá-los além dos limites de uso? Talvez eu esteja pensando demais sobre isso, mas não deveria haver algo para autenticar que uma solicitação foi verificada para o proprietário do apikey? No meu caso, esse era o objetivo do apisecret, ele nunca é mostrado / transmitido sem ser hash.

Falando em hashes, e o MD5 vs hmac-sha1? Realmente importa quando todos os valores são misturados com dados suficientemente longos (isto é, apisecret)?

Antes, eu estava pensando em adicionar um sal por usuário / linha ao hash de senha dos meus usuários. Se eu fizesse isso, como o aplicativo poderia criar um hash correspondente sem conhecer o sal usado?

jsuggs
fonte
1
Esperava receber mais alguns comentários / sugestões. A pergunta é muito vaga / ambígua?
jsuggs
6
a pergunta é perfeita, mas, mesmo quase 2 anos depois, as implementações oauth parecem arcanas ... estou tendo mais dificuldade em conseguir exatamente o que você discutiu acima. tenho uma dimensão adicional: não quero usar um par de login / senha - quero usar a verificação de identidade do google no android / ios (o symbian foi declarado pelo WWF uma "espécie quase extinta") e me recuso a desenvolver para Windows Mobile (como eles chamam hoje em dia).
gil tony
8
seu ridículo que, tanto quanto todo mundo sugere OAuth 2.0 ive ainda encontrar um tutorial clara, simples ou exemplo que usos comuns Inglês para explicar os passos, requisitos, fazer e donts ect ....
ChuckKelly
2
Leia este fluxo específico de OAuth2.0 (fluxo de senha do proprietário do recurso). Não há redirecionamento para o site. techblog.hybris.com/2012/06/11/…
Franklin
1
Também estou procurando a mesma resposta. Encontrei um bom artigo que foi escrito recentemente. Eu espero que isso ajude. stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
Novo no Rails

Respostas:

44

A maneira como estou pensando em fazer a parte de login disso nos meus projetos é:

  1. Antes de efetuar o login, o usuário solicita um login_tokendo servidor. Eles são gerados e armazenados no servidor mediante solicitação e provavelmente têm uma vida útil limitada.

  2. Para efetuar login no aplicativo, calcula o hash da senha do usuário e, em seguida, faz o hash da senha com o login_tokenvalor de obter um valor; eles retornam login_tokeno hash combinado e o hash.

  3. O servidor verifica o login_tokenque ele gerou, removendo-o da sua lista de login_tokens válidos . O servidor então combina seu hash armazenado da senha do usuário com login_tokenoe garante que ele corresponda ao token combinado enviado. Se corresponder, você autenticou seu usuário.

As vantagens disso são que você nunca armazena a senha do usuário no servidor, a senha nunca é passada de forma clara, o hash da senha é passado apenas de forma clara na criação da conta (embora possa haver maneiras de contornar isso), e deve ser protegido contra ataques de repetição, pois ele login_tokené removido do banco de dados em uso.

Michael Anderson
fonte
Obrigado, esqueci de adicionar a parte sobre hash da senha no lado do aplicativo. Não guardo as senhas dos meus usuários de maneira clara (eu tenho o hash antes de armazenar).
jsuggs
2
Vejo uma desvantagem deste método: você não pode armazenar senhas salgadas no DB. Se os invasores colocarem as mãos no seu banco de dados, eles não precisarão descriptografar. Como o hash da senha é a senha real nesse esquema.
sigod 11/11
2
@sigod Você está correto. Embora eu ache que há uma dicotomia fundamental por lá - você precisa confiar no seu transporte ou no armazenamento. Os sistemas de login que usam senhas salgadas confiam na camada de transporte - e, portanto, passam a senha do usuário para o sistema de autenticação. Este caso não confia na camada de transporte (acho que foi porque a plataforma que eu estava alvejando tinha suporte ruim para o SHTTP). Se você confiar na camada de transporte, poderá fazer outras compensações.
Michael Anderson
Tenho 3 problemas: 1) como a senha do usuário nunca é armazenada no servidor? na etapa 2, você mencionou que ele armazena a senha do usuário com hash. 2) A senha do usuário nunca é passada de forma clara. Mas, na verdade, ele é hash no cliente e, em seguida, comparado com a senha hash no servidor, que é quase a mesma que passar e armazená-la de forma clara, qual é o sentido de fazer isso? 3) Esse método pressupõe que o invasor não sabe como o login_token + a senha é dividida em hash, o que viola o princípio de Kerckhoffs e o torna realmente inseguro.
Tamer Shlash
14

São muitas perguntas em uma, acho que muitas pessoas não conseguiram ler até o fim :)

Minha experiência na autenticação de serviços da Web é que as pessoas geralmente fazem o excesso de engenharia e os problemas são os mesmos que você encontraria em uma página da Web. Possíveis opções muito simples incluem https para a etapa de login, retornam um token, exigem que ele seja incluído em solicitações futuras. Você também pode usar a autenticação básica http e apenas passar coisas no cabeçalho. Para aumentar a segurança, gire / expire os tokens com frequência, verifique se as solicitações são provenientes do mesmo bloco IP (isso pode ficar confuso, pois os usuários móveis se movem entre as células), combinado com a chave da API ou similar. Como alternativa, execute a etapa "solicitar chave" do oauth (alguém já sugeriu isso em uma resposta anterior e é uma boa idéia) antes de autenticar o usuário e use-a como uma chave necessária para gerar o token de acesso.

Uma alternativa que eu ainda não usei, mas já ouvi falar muito como alternativa ao oAuth, compatível com dispositivos, é o xAuth . Dê uma olhada e, se você usá-lo, eu ficaria realmente interessado em saber quais são suas impressões.

Para o hash, o sha1 é um pouco melhor, mas não se preocupe - o que os dispositivos puderem implementar facilmente (e rapidamente no sentido de desempenho) provavelmente está bom.

Espero que ajude, boa sorte :)

Lorna Mitchell
fonte
Obrigado pela resposta. Eu estive pesquisando no xAuth e essa pode ser a rota a seguir, para que eu possa terminar com uma instalação do oAuth, o que contribui para um processo mais padronizado de interação com a API.
jsuggs
9

Então, o que você procura é algum tipo de mecanismo de autenticação no servidor que lide com os aspectos de autenticação e autorização de um aplicativo móvel?

Supondo que esse seja o caso, então eu abordaria da seguinte maneira (mas apenas porque eu sou um desenvolvedor Java, então um cara de C # faria isso de maneira diferente):

O serviço de autenticação e autorização RESTful

  1. Isso funcionará apenas em HTTPS para evitar a interceptação.
  2. Ele será baseado em uma combinação de RESTEasy , Spring Security e CAS (para logon único em vários aplicativos).
  3. Ele funcionará com navegadores e aplicativos clientes habilitados para a Web
  4. Haverá uma interface de gerenciamento de contas baseada na Web para permitir que os usuários editem seus detalhes e administradores (para aplicativos específicos) para alterar os níveis de autorização

A biblioteca / aplicativo de segurança do lado do cliente

  1. Para cada plataforma suportada (por exemplo, Symbian, Android, iOS etc.), crie uma implementação adequada da biblioteca de segurança no idioma nativo da plataforma (por exemplo, Java, ObjectiveC, C etc.)
  2. A biblioteca deve gerenciar a formação de solicitação HTTPS usando as APIs disponíveis para a plataforma fornecida (por exemplo, Java usa URLConnection etc.)
  3. Os consumidores da biblioteca geral de autenticação e autorização (porque isso é tudo) codificarão para uma interface específica e não ficarão felizes se alguma vez mudar, portanto, verifique se é muito flexível. Siga as opções de design existentes, como Spring Security.

Então agora que a visão de 30.000 pés está completa, como você faz isso? Bem, não é tão difícil criar um sistema de autenticação e autorização com base nas tecnologias listadas no lado do servidor com um cliente de navegador. Em combinação com HTTPS, as estruturas fornecerão um processo seguro com base em um token compartilhado (geralmente apresentado como um cookie) gerado pelo processo de autenticação e usado sempre que o usuário desejar fazer algo. Esse token é apresentado pelo cliente ao servidor sempre que ocorre uma solicitação.

No caso do aplicativo móvel local, parece que você está procurando uma solução que faça o seguinte:

  1. O aplicativo cliente possui uma lista de controle de acesso (ACL) definida que controla o acesso do tempo de execução às chamadas de método. Por exemplo, um determinado usuário pode ler uma coleção de um método, mas sua ACL só permite acesso a objetos que possuem um Q no nome, de modo que alguns dados da coleção são inutilmente puxados pelo interceptador de segurança. Em Java, isso é simples, basta usar as anotações do Spring Security no código de chamada e implementar um processo de resposta ACL adequado. Em outros idiomas, você está por conta própria e provavelmente precisará fornecer um código de segurança padrão que chama na sua biblioteca de segurança. Se o idioma suportar AOP (Aspect Oriented Programming), utilize-o ao máximo para esta situação.
  2. A biblioteca de segurança armazena em cache a lista completa de autorizações na memória privada do aplicativo atual, para que ele não precise permanecer conectado. Dependendo da duração da sessão de logon, essa pode ser uma operação pontual que nunca se repete.

Faça o que fizer, não tente inventar seu próprio protocolo de segurança ou use a segurança pela obscuridade. Você nunca poderá escrever um algoritmo melhor para isso do que aqueles que estão disponíveis no momento e são gratuitos. Além disso, as pessoas confiam em algoritmos conhecidos. Portanto, se você disser que sua biblioteca de segurança fornece autorização e autenticação para aplicativos móveis locais usando uma combinação de tokens criptografados SSL, HTTPS, SpringSecurity e AES, você terá imediatamente credibilidade no mercado.

Espero que isso ajude e boa sorte com seu empreendimento. Se você quiser obter mais informações, informe-me - escrevi alguns aplicativos da Web baseados em Spring Security, ACLs e similares.

Gary Rowe
fonte
Obrigado, boa informação. Par de perguntas. Primeiro, se a espionagem é aceitável (não tenho certeza se é / não é, meu aplicativo em mente não tem nenhuma informação pessoal / valiosa real, mas se isso mudasse minha lógica), então o HTTPS é realmente necessário?
Jsuggs 28/10/10
Você pode operar o sistema geral fora do HTTPS, se quiser. HTTPS é apenas para proteger informações secretas, então eu presumo que durante a fase de autenticação você faria isso por meio do HTTPS para fornecer alguma garantia de que seu nome de usuário / senha / segredo é mantido em segredo. Depois que o token é entregue na resposta, outras solicitações podem ser feitas com clareza se as informações contidas no fluxo (que exigiam autenticação para obter) não precisam de proteção contra interceptadores.
Gary Rowe
Além disso, essa descrição do protocolo de autenticação CAS pode ser útil: jasig.org/cas/protocol #
Gary Rowe
9

O Twitter solucionou o problema de aplicativo externo no oAuth, suportando uma variante que eles chamam de xAuth . Infelizmente, já existem vários outros esquemas com esse nome, portanto pode ser confuso resolver o problema.

O protocolo é oAuth, exceto que ignora a fase do token de solicitação e simplesmente emite imediatamente um par de token de acesso após o recebimento de um nome de usuário e senha. (Começando na etapa E aqui .) Essa solicitação e resposta inicial devem ser protegidas- está enviando o nome de usuário e a senha em texto sem formatação e recebendo de volta o token de acesso e o token secreto. Depois que o par de tokens de acesso for configurado, se a troca de tokens inicial foi por meio do modelo oAuth ou do modelo xAuth é irrelevante para o cliente e o servidor pelo restante da sessão. Isso tem a vantagem de poder aproveitar a infraestrutura existente do oAuth e ter quase a mesma implementação para aplicativos móveis / web / desktop. A principal desvantagem é que o aplicativo recebe acesso ao nome de usuário e senha do cliente, mas parece que seus requisitos exigem essa abordagem.

De qualquer forma, gostaria de concordar com a sua intuição e a de vários outros respondentes aqui: não tente criar algo novo do zero. Os protocolos de segurança podem ser fáceis de iniciar, mas sempre são difíceis de executar, e quanto mais complicados eles se tornam, menor a probabilidade de seus desenvolvedores de terceiros poderem implementar contra eles. Seu protocolo hipotético é muito semelhante ao o (x) Auth - api_key / api_secret, nonce, sha1 hashing - mas em vez de poder usar uma das muitas bibliotecas existentes que seus desenvolvedores precisarão usar por conta própria.

lantius
fonte
2
Devo também salientar que parece que o terminal 'ignorar solicitação de token' estará no oAuth 2; ele está listado no rascunho atual como o tipo de concessão de acesso "senha". Consulte a seção 4.1.2: tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
lantius
Como mencionei para Lonra, estou estudando mais o xAuth e, especificamente, pelas razões mencionadas no final ... desenvolvedores podem "de prateleira" oAuth ferramentas / bibliotecas para interagir com minha API, o que é "uma coisa boa" .
Jsuggs # 30/10
6

Cheguei tarde demais para a festa, mas eu queria mencionar alguns pontos adicionais a serem considerados para qualquer pessoa interessada nessa questão. Eu trabalho para uma empresa que cria soluções de segurança de API móvel ( approov ), portanto toda essa área é definitivamente relevante para meus interesses.

Para começar, a coisa mais importante a considerar ao tentar proteger uma API móvel é quanto vale para você . A solução certa para um banco é diferente da solução certa para alguém que apenas faz as coisas por diversão.

Na solução proposta, você menciona que serão necessários no mínimo três parâmetros:

  • apikey - dado ao desenvolvedor no registro
  • timestamp - funciona como um identificador exclusivo para cada mensagem de um determinado apikey
  • hash - um hash do timestamp + o apisecret

A implicação disso é que, para algumas chamadas de API, não é necessário nome de usuário / senha. Isso pode ser útil para aplicativos em que você não deseja forçar um login (navegando em lojas on-line, por exemplo).

Esse é um problema ligeiramente diferente do da autenticação do usuário e é mais parecido com a autenticação ou atestado do software. Não há usuário, mas você ainda deseja garantir que não haja acesso malicioso à sua API. Então você usa seu segredo da API para assinar o tráfego e identificar o código que acessa a API como genuíno. O possível problema com esta solução é que você precisará revelar o segredo em todas as versões do aplicativo. Se alguém puder extrair o segredo, poderá usar sua API, personificando seu software, mas fazendo o que quiser.

Para combater essa ameaça, há várias coisas que você pode fazer, dependendo da importância dos dados. A ofuscação é uma maneira simples de dificultar a extração do segredo. Existem ferramentas que farão isso por você, mais ainda no Android, mas você ainda precisa ter um código que gere seu hash e um indivíduo suficientemente qualificado pode sempre chamar a função que faz o hash diretamente.

Outra forma de atenuar contra o uso excessivo de uma API que não requer um login é estrangular o tráfego e potencialmente identificar e bloquear endereços IP suspeitos. A quantidade de esforço que você deseja fazer dependerá em grande parte da validade dos seus dados.

Além disso, você pode facilmente começar a entrar no domínio do meu trabalho diário. De qualquer forma, é outro aspecto da segurança de APIs que eu acho importante e queria sinalizar.

ThePragmatist
fonte