Estou no processo de projetar 3 componentes que funcionarão em sinfonia entre si:
- Um serviço da Web RESTful que requer
BasicAuth
HTTPS 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 GET
para algum recurso), as BasicAuth
credenciais 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?
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:
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é
fonte