Segurança da API REST Token armazenado vs JWT vs OAuth

104

Ainda estou tentando encontrar a melhor solução de segurança para proteger a API REST, porque a quantidade de aplicativos móveis e API está aumentando a cada dia.

Tentei diferentes formas de autenticação, mas ainda tenho alguns mal-entendidos, por isso preciso de conselhos de alguém mais experiente.

Deixe-me dizer, como eu entendo todas essas coisas. Se eu entender algo incorretamente, entre em contato.

Quanto à API REST é sem estado e WEB em geral, precisamos enviar alguns dados de autenticação em cada solicitação (cookies, token ...). Conheço três mecanismos amplamente utilizados para autenticar usuários

  1. Token com HTTPS. Eu tenho usado essa abordagem muitas vezes, é boa o suficiente com HTTPS. Se o usuário fornecer a senha e o login corretos, ele receberá o token em resposta e o utilizará para as solicitações adicionais. O token é gerado pelo servidor e armazenado, por exemplo, na tabela separada ou a mesma onde as informações do usuário são armazenadas. Portanto, para cada servidor de solicitação, verifique se o usuário possui token e é o mesmo que no banco de dados. Tudo é bem direto.

  2. Token JWT. Esse token é auto-descritivo, contém todas as informações necessárias sobre o próprio token, o usuário não pode alterar, por exemplo, data de validade ou qualquer outra reivindicação, porque esse token é gerado (assinado) pelo servidor com a palavra-chave secreta. Isso também está claro. Mas um grande problema, pessoalmente, para mim, como invalidar o token.

  3. OAuth 2. Não entendo por que essa abordagem deve ser usada quando a comunicação é estabelecida diretamente entre servidor e cliente. Pelo que entendi, o servidor OAuth é usado para emitir token com escopo restrito para permitir que outros aplicativos acessem informações do usuário sem armazenar senha e logon. Esta é uma ótima solução para as redes sociais, quando o usuário deseja se inscrever em alguma página, o servidor pode solicitar permissões para obter informações do usuário, por exemplo, do twitter ou do facebook, preencher campos de registro com dados do usuário e assim por diante.

Considere o cliente móvel para a loja online.

Primeira pergunta: devo preferir o JWT ao invés do primeiro tipo de token? Na medida em que eu preciso de usuário de logon / logout no cliente móvel, preciso armazenar um token em algum lugar ou, no caso de JWT, o token deve ser invalidado no logout. Diferentes abordagens são usadas para invalidar o token, uma das é criar lista de tokens inválidos (lista negra). Hmm. A tabela / arquivo terá um tamanho muito maior do que se o token estivesse armazenado na tabela e associado ao usuário e apenas removido no logout.

Então, quais são os benefícios do token JWT?

Segunda pergunta sobre o OAuth, devo usá-lo em caso de comunicação direta com meu servidor? Qual é o objetivo de mais uma camada entre cliente e servidor apenas para emitir token, mas a comunicação não será com o servidor oauth, mas com o servidor principal. Pelo que entendi, o servidor OAuth é responsável apenas por conceder permissões (tokens) a aplicativos de terceiros para acessar informações privadas do usuário. Mas meu aplicativo cliente móvel não é de terceiros.

CROSP
fonte
Obrigado, eu queria saber isso recentemente. Fui com o gerenciamento de sessões (Beaker) e excluo os tokens de sessão depois de uma hora. Oauth não parecia o ajuste certo.
JasTonAChair 08/12/16

Respostas:

86

Considere o primeiro caso. Cada cliente obtém um ID aleatório que dura a duração da sessão - que pode demorar vários dias, se você desejar. Em seguida, você armazena as informações relevantes para essa sessão em algum lugar do servidor. Pode estar em um arquivo ou em um banco de dados. Vamos supor que você passe o ID por meio de um cookie, mas você pode usar o URL ou um cabeçalho HTTP.

IDs de sessão / Cookies

Prós:

  • Fácil de codificar o cliente e o servidor.
  • Fácil de destruir uma sessão quando alguém se desconecta.

Contras:

  • O lado do servidor precisa periodicamente excluir sessões expiradas nas quais o cliente não efetuou logout.
  • Toda solicitação HTTP requer uma pesquisa no armazenamento de dados.
  • Os requisitos de armazenamento aumentam à medida que mais usuários têm sessões ativas.
  • Se houver vários servidores HTTP front-end, os dados da sessão armazenada precisarão ser acessíveis por todos eles. Isso pode ser um pouco mais trabalhoso do que armazená-lo em um servidor. Os problemas maiores são que o armazenamento de dados se torna um ponto único de falha e pode se tornar um gargalo.

Tokens da Web JSON (JWT)

No segundo caso, os dados são armazenados em um JWT que é passado ao invés de no servidor.

Prós:

  • Os problemas de armazenamento do lado do servidor se foram.
  • O código do lado do cliente é fácil.

Contras:

  • O tamanho do JWT pode ser maior que um ID de sessão. Isso pode afetar o desempenho da rede, pois é incluído em cada solicitação HTTP.
  • Os dados armazenados no JWT são legíveis pelo cliente. Isso pode ser um problema.
  • O lado do servidor precisa de código para gerar, validar e ler JWTs. Não é difícil, mas existe uma curva de aprendizado e a segurança depende disso.

    Qualquer pessoa que obtenha uma cópia da chave de assinatura pode criar JWTs. Você pode não saber quando isso acontece.

    Havia (há?) Um bug em algumas bibliotecas que aceitavam qualquer JWT assinado com o algoritmo "none" para que qualquer um pudesse criar JWTs nos quais o servidor confiaria.

  • Para revogar um JWT antes que ele expire, é necessário usar uma lista de revogação. Isso leva você de volta aos problemas de armazenamento do lado do servidor que você estava tentando evitar.

OAuth

Geralmente, o OAuth é usado para autenticação (ou seja, identidade), mas pode ser usado para compartilhar outros dados, como uma lista de conteúdo que o usuário comprou e tem o direito de fazer o download. Também pode ser usado para conceder acesso à gravação em dados armazenados por terceiros. Você pode usar o OAuth para autenticar usuários e, em seguida, usar armazenamento do lado do servidor ou JWT para os dados da sessão.

Prós:

  • Nenhum código para os usuários se inscreverem ou redefinirem sua senha.
  • Nenhum código para enviar um email com um link de validação e validar o endereço.
  • Os usuários não precisam aprender / anotar outro nome de usuário e senha.

Contras:

  • Você depende de terceiros para que seus usuários usem seu serviço. Se o serviço for interrompido ou se o interromper, você precisará descobrir outra coisa. Por exemplo: como você migra os dados da conta do usuário se a identidade deles mudar de "[email protected]" para "[email protected]"?
  • Normalmente você precisa escrever um código para cada provedor. por exemplo, Google, Facebook, Twitter.
  • Você ou seus usuários podem ter preocupações com a privacidade. Os provedores sabem quais usuários usam seu serviço.
  • Você está confiando no provedor. É possível que um provedor emita tokens válidos para um usuário para outra pessoa. Isso pode ser para fins legais ou não.

Diversos

  • Os IDs de sessão e os JWTs podem ser copiados e usados ​​por vários usuários. Você pode armazenar o endereço IP do cliente em um JWT e validá-lo, mas isso impede que os clientes em roaming digam Wi-Fi para celular.
Chad Clark
fonte
Para adicionar à sua resposta, o outh pode não ser útil quando o usuário deseja se inscrever usando as contas da empresa que normalmente não são associadas ou vinculadas a nenhum site de rede social ou ao google.
Aftab Naveed
5
Não sei por que essa é a resposta aceita? não responder a pergunta real, apenas reformar a questão de outra forma
amd
1
Você diz: "Os dados armazenados no JWT são legíveis pelo cliente. Isso pode ser um problema. Por que não usar o JWE se isso é um problema?"
Silver
Esta resposta confunde maçãs e laranjas. Você não deve compará-los com o OAuth 2.0 (a especificação "autorização"). O que o OP precisa saber é: "Fluxo de senha do proprietário do recurso" - que é autenticação como uma concessão.
Onur Yıldırım
5

Pergunte a si mesmo por que você precisa invalidar o token original.

Um usuário efetua login, um token é gerado e o aplicativo é desativado.

O usuário pressiona o logout, um novo token é gerado e substitui o token original. Mais uma vez, está tudo bem.

Você parece estar preocupado com o caso em que os dois tokens ficam por aqui. E se o usuário fizer logout e, de alguma forma, fizer uma solicitação usando o token conectado. Quão realista é esse cenário? É apenas um problema durante o logout ou há muitos cenários possíveis em que vários tokens podem ser um problema?

Eu mesmo não acho que vale a pena se preocupar. Se alguém estiver interceptando e decodificando seus dados https criptografados, você terá problemas muito maiores.

Você pode oferecer proteção adicional colocando um tempo de expiração no token original. Então, se acabar sendo roubado ou algo assim, seria bom apenas por um curto período de tempo.

Caso contrário, acho que você precisaria ter informações de estado no servidor. Não coloque na lista negra os tokens, mas coloque na lista branca a assinatura do token atual.

Cerad
fonte
2
Se você presumir que alguns de seus clientes são mal-intencionados, é fácil ver que uma sessão será copiada e reutilizada, e você deve combater isso no servidor.
Michael Shaw
1
Má idéia, isso pode ser usado mais tarde por hackers, ou apenas
brutalmente
2
Imagine que um usuário deseja sair de todos os outros dispositivos, usando o JWT não é possível.
amd
@amd não é possível? E se eu adicionar o nonce = (aleatório) e se o usuário fizer logout, substitua o nonce. Parece simples e eficaz.
Simon B.
3

Você pode lidar com os problemas de JWT mencionados, armazenando um valor de salt junto com o usuário e usando o salt como parte do token para o usuário. Então, quando você precisar invalidar o token, basta alterar o sal.

Sei que já faz alguns anos, mas na verdade faria isso de forma diferente agora. Acho que garantiria que os tokens de acesso tivessem uma vida útil relativamente curta, digamos uma hora. Também usaria tokens de atualização com estado no servidor e, quando desejasse encerrar a sessão de alguém, revogaria o token de atualização removendo-o do servidor. Depois de uma hora, o usuário seria desconectado e precisaria fazer login novamente para recuperar o acesso.

RibaldEddie
fonte
4
Mas, novamente, torna-se o estado-cheia neste caso, então o que é a razão para criar sal ou usar qualquer outra abordagem, você pode simples token de loja na tabela e excluir, quando deveria ser invalidado
CROSP
2
Você também pode invalidar com base no tempo.
RibaldEddie
Qual é a diferença entre o tempo de expiração neste caso? Como posso invalidar o token com base no tempo em que o usuário deseja sair do cliente móvel? Parece que não há como a API ficar sem estado nesse caso. Qual é a solução mais adequada e segura?
CROSP
2
O mais adequado para o logout de um único dispositivo é garantir que você use um clientId além do salt. Sugiro que você analise a especificação do token do portador Oauth-jwt para obter informações.
RibaldEddie
Obrigado pela resposta, mas não entendo por que devo usar o OAuth neste caso.
CROSP