Opções de autenticação para sistemas distribuídos


9

Estou no processo de projetar 3 componentes que funcionarão em sinfonia entre si:

  • Um serviço da Web RESTful que requer BasicAuthHTTPS em todas as chamadas e é o que realmente faz todo o trabalho pesado para o meu sistema (faz o trabalho)
  • Uma interface da web que converte ações do usuário final em chamadas de API para o serviço da web mencionado acima; portanto, a interface do usuário é "apoiada por" o WS
  • Uma ferramenta da interface da linha de comandos (CLI) que os desenvolvedores podem instalar e executar localmente, que também converte comandos em chamadas de API para o WS (portanto, também é "suportada" pelo WS)

Um dos primeiros obstáculos que estou tentando superar é no que diz respeito à autenticação e autorização.

Vamos fingir que o WS usa um serviço de diretório / LDAP (como o AD ou talvez o Apache DS) como região de autenticação. Ou seja, quando uma chamada de API é recebida por fio (digamos, um HTTPS GETpara algum recurso), as BasicAuthcredenciais são extraídas da solicitação e encaminhadas ao serviço LDAP para determinar se este é um usuário válido ou não. Se eles estiverem autenticados, digamos que um domínio de autorização separado, talvez um banco de dados, seja usado para determinar se o usuário identificado pode ou não fazer o que está tentando na solicitação HTTPS. Por enquanto, tudo bem.

No caso da ferramenta CLI, o usuário terá que se autenticar antes de executar qualquer comando e, portanto, esse modelo funcionará perfeitamente, pois um único usuário estará sempre operando a mesma instância da CLI em um determinado momento.

O problema surge quando tentamos integrar o aplicativo Web (UI) ao WS, porque muitas pessoas podem fazer logon no aplicativo ao mesmo tempo, todas com permissões diferentes, determinando quais chamadas de API subjacentes podem fazer.

Tanto quanto eu vejo, parece que tenho apenas quatro opções aqui:

  • Credenciais em cache : depois de fazer login no aplicativo, as credenciais são armazenadas em algum lugar em cache (de modo que o aplicativo tenha acesso a elas), e o aplicativo não impõe nenhum tipo de política de autorização. Quando os usuários tentam fazer coisas que geram chamadas de API ocultas, suas credenciais são consultadas no cache e encaminhadas com as chamadas de API. Se o WS determinar que não está autorizado, ele retornará um erro.
  • Contas em nível de serviço : o aplicativo e o WS usam os mesmos domínios de autenticação / autorização, exceto que a interface do usuário da Web agora impõe autorização sobre o que os usuários podem realmente ver e fazer dentro do aplicativo. Se eles têm permissão para fazer algo que gera uma chamada de API subjacente, o aplicativo envia credenciais da conta de serviço (por exemplo myapp-admin-user) com cada chamada de API em nome do usuário.
  • OAuthv2 : Não tenho idéia do que é o OAuth ou se é aplicável a esse cenário, mas sinto que pode ser uma solução aqui de alguma forma.
  • Servidores de token : use um servidor de token, como o CAS ou talvez o Kerberos, para garantir aos usuários, da mesma maneira que a opção Conta de nível de serviço se comporta. Aqui, quando um usuário faz login no aplicativo com sucesso, o servidor de token envia o aplicativo de volta a um UUID de sessão e também registra esse UUID no WS. Toda vez que o aplicativo gera uma chamada de API, ele adere o UUID à solicitação, que é validada no lado do WS.

A opção " Credenciais em cache " parece uma aberração de tudo o que é bom e saudável em áreas de segurança. Parece errado armazenar em cache credenciais em qualquer lugar, sempre.

A opção " Token Server " parece válida para uma configuração do tipo SSO, mas não nesse caso específico e me parece estranha. Também acho que não há uma boa maneira de usar o conceito UUID da sessão e BasicAuth / HTTPS ao mesmo tempo.

Portanto, isso deixa o OAuthv2, do qual eu não conheço nada, e " SLA (Conta de nível de serviço) * " como as únicas opções restantes. A opção SLA parece boa, mas tem algumas desvantagens a seguir:

  • Requer que a conta de serviço tenha basicamente "privilégios de Deus" sobre o WS. Em outras palavras, uma vez que o aplicativo julgue que um usuário pode clicar em um botão ou fazer algo na interface do usuário, isso se traduz em uma chamada incondicional à API pela conta de serviço usada pela interface do usuário. Isso parece ruim, ok?
  • Ocorre-me que manter dois conjuntos de permissões (o conjunto de permissões para cada usuário do aplicativo e, em seguida, o conjunto de permissões da conta de serviço usada pelo aplicativo no WS) pode resultar na perda de sincronia entre as permissões. de alguma forma

Parece que eu realmente não tenho boas opções aqui. Certamente não posso ser o primeiro desenvolvedor a se deparar com isso, mas pedir aos deuses do Google não me ajudou muito aqui. Alguma ideia?

Respostas:


6

Há muitos motivos para não usar o esquema de autenticação básica para proteger os serviços de API da Web.

Para usar o serviço, o cliente precisa manter a senha em algum lugar em texto não criptografado para enviá-la junto com cada solicitação.

A verificação de uma senha deve ser muito lenta (para combater ataques de força bruta), o que prejudicaria a escalabilidade do seu serviço. Por outro lado, a validação do token de segurança pode ser rápida (verificação de assinatura digital).

O OAuth2 oferece soluções para cada um dos seus casos de uso. Seu aplicativo da web pode usar a concessão de código , que fornece um token de acesso que pode ser usado para conversar com sua API.

Seu aplicativo da Web redirecionará o navegador do usuário para o servidor de autorização. Ele solicitará ao usuário credenciais (ou cartão inteligente ou código de autenticação de dois fatores) e retornará um código ao navegador, que o cliente (seu aplicativo da Web) pode usar para obter um token de acesso do servidor de autorização.

Seu aplicativo também receberá um token de atualização com o qual poderá obter um novo token de acesso se o token atual expirar.

Seu aplicativo CLI pode usar a concessão de credenciais do proprietário do recurso . Você solicitará credenciais ao usuário e as enviará ao servidor de autorização para adquirir um token de acesso e atualização. Depois que o aplicativo CLI tiver o token, você poderá descartar a senha do usuário na memória.

Ambos os clientes (aplicativo da web e cliente de linha de comando) precisam ser registrados com antecedência no servidor de autorização.

O servidor de autorização pode conversar com um serviço de diretório / LDAP (provedor de identidade ou IdP) para fazer a autenticação real.

Seu serviço de API da web precisa apenas verificar o token JWT recebido e estabelecer o que o usuário tem permissão para fazer (autorização).

Se você for vítima de um ataque intermediário e perder seu token de acesso, o invasor terá apenas um tempo limitado (tempo de vida do token) para usá-lo. Uma senha normalmente é válida por muito mais tempo. Os tokens de atualização podem ser revogados caso sejam perdidos.


Obrigado pela entrada sólida @ user18044 (+1). E os outros clientes HTTP para o serviço da web? Este é um serviço da Web RESTful, para que qualquer pessoa possa criar clientes para ele. Que opção do OAuthv2 eles usariam para autenticar cada solicitação? O mesmo que o aplicativo Web (concessão de código)? Obrigado novamente!
smeeb

@ User18044 também pode confirmar que o OAuthv2 trata apenas do aspecto da autenticação e não da autorização? Em caso afirmativo, como eu poderia mapear cada solicitação autenticada (bem-sucedida) para um conjunto de funções / permissões disponíveis para o cliente?
smeeb

1
Dependendo de como você confia nesses clientes, eles são autenticados de maneira diferente. Digamos, por exemplo, que você construa um aplicativo móvel para sua própria API, poderá usar a concessão de credenciais do proprietário do recurso. Mas se o cliente móvel for criado por terceiros (algum aplicativo da loja de aplicativos), você usaria uma concessão implícita.
MTVD 28/07

1
@smeeb OAuth define escopos para indicar o que o cliente pode fazer. Há vários escopos predefinidos, mas você pode definir seus próprios (por exemplo, para chamar APIs específicas (consulte tools.ietf.org/html/rfc6749#section-3.3 )
MvdD

1
Não se preocupe, você é bem-vindo. Os escopos são realmente um mecanismo para determinar o que terceiros podem fazer na sua API. Por exemplo, um aplicativo financeiro que só pode ler o saldo da sua conta no site do seu banco. Porém, como o token JWT contém o nome do usuário e, opcionalmente, funções pares, é possível procurar em um banco de dados o que um usuário ou usuário em uma função tem permissão para fazer. É também assim que minha empresa está fazendo isso.
MTVD 29/07

2

Estou trabalhando em um sistema um pouco parecido agora, na verdade; Eu mentiria se dissesse que sabia a maneira "certa" de fazer isso funcionar, pois ainda estou experimentando, mas talvez repassar o que descobri que funcione pode ajudar. A configuração é bastante inspirada no OAuth2, apesar de suas desvantagens , algumas das quais discutirei.

AVISO LEGAL: Eu não sou um profissional de segurança, e o que eu construí, construí com a ajuda do Google e com o maior número de exemplos possível.

Quando comecei a pesquisar como criaria a API da web que apoiaria os aplicativos clientes, decidi que queria tentar tornar a API o mais estável possível. Parte de mim ficou tentada a buscar autenticação básica HTTP e tornar os usuários autenticados em todas as solicitações, mas surgiram dois problemas que fizeram com que a solução não parecesse viável:

  1. A pesquisa para validar as credenciais é uma despesa de tempo não trivial, pois envolveria pelo menos uma chamada de banco de dados a cada solicitação
  2. O sistema é um sistema multilocatário; identificar a qual inquilino o usuário pertencia exigiria um terceiro parâmetro e que não é suportado pela autenticação básica HTTP (1)

As complexidades envolvidas na autenticação me fizeram optar por um sistema de token, onde o usuário fazia uma solicitação de autenticação para um terminal que emitia um token de identificação e depois armazenava em algum lugar que o servidor pudesse usá-lo posteriormente para validar solicitações e vinculá-lo a alguns dados de usuário necessários. Não é perfeitamente apátrida e estive analisando os tokens da Web JSON como uma abordagem alternativa, mas a pesquisa de tokens pode ser feita muito rapidamente. 2)

Os clientes então se apegam a esse token até que o servidor não aceite mais o token. O cliente tenta se autenticar novamente com o servidor e recuperar um novo token para autenticar solicitações futuras. É isso que sua postagem faz referência como a estratégia de credenciais em cache, e optamos por usá-la porque nos permite manter mais controle sobre o acesso ao aplicativo. Desde que o cliente possa confiar em suas próprias informações de autorização e esteja se conectando apenas por uma conexão segura (forçamos o acesso somente HTTPS por esse motivo), essa não é necessariamente uma maneira ruim de lidar com as coisas, mesmo que seja da perspectiva de UX. Para o serviço da Web, na verdade, mantemos o token no armazenamento local do navegador; como é apenas uma identificação temporária e não a combinação real de nome de usuário / senha do usuário, consideramos isso "

Os tokens são então enviados para a API da web como parte de um cabeçalho de autorização ou como um parâmetro GET para clientes em que os cabeçalhos HTTP personalizados não estão disponíveis. Isso é importante porque permite uma maior flexibilidade na maneira como acessamos a API a partir de uma ampla variedade de aplicativos clientes em potencial, como você precisa dar suporte a uma CLI e um aplicativo Web. Os tokens de portador são uma coisa bastante comum, mas não são exatamente perfeitos . No entanto, as preocupações com a segurança do aplicativo não são suficientemente importantes para dedicar tempo adicional para melhorar isso.

Depois que o token é validado, a autorização entra em jogo. O que isso implica pode variar bastante, mas nesse ponto no aplicativo a identidade do usuário é conhecida e, portanto, um serviço de autorização de algum tipo precisa receber a identidade do usuário e o objeto / ação a serem verificados.

No mínimo, se você deseja usar esse tipo de estratégia, há muitas bibliotecas projetadas para implementar o OAuth e o OAuth2 por aí; a menos que você seja como nós e tenha alguns requisitos adicionais, recomendo o uso de uma biblioteca de segurança de terceiros confiável, pois é provável que você não consiga acertar as coisas na primeira vez que tentar. Eu ainda procuro uma alternativa de terceiros para substituir nosso sistema de autenticação atual, porque sei que está cheio de buracos e casos extremos que nem consigo imaginar.


Notas de rodapé

  1. Isso não seria necessário se nosso sistema fosse construído de maneira diferente, digamos, usando pontos de entrada diferentes para cada cliente; alternativamente, eu também considerei ser inteligente e prefixar o nome de usuário com um identificador de inquilino
  2. Eu tive algumas idéias sobre como facilitar a validação da cadeia de tokens puramente computacionalmente, em vez de ter que fazer uma pesquisa de E / S como um objetivo de melhoria a longo prazo; no mínimo, os tokens contêm um byte de versão que permitirá atualizações na linha se / quando o processo de decodificação for alterado
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.