E se o JWT for roubado?

201

Estou tentando implementar a autenticação sem estado com o JWT para minhas APIs RESTful.

AFAIK, JWT é basicamente uma sequência criptografada passada como cabeçalhos HTTP durante uma chamada REST.

Mas e se houver um bisbilhoteiro que veja a solicitação e roube o token ? Então ele será capaz de falsificar pedidos com a minha identidade?

Na verdade, essa preocupação se aplica a toda autenticação baseada em token .

Como evitar isso? Um canal seguro como HTTPS?

smwikipedia
fonte
1
É por isso que os tokens geralmente são válidos apenas por um curto período de tempo. E sim, você deve usar HTTPS se estiver preocupado com a confidencialidade de seus dados.
Jonathon Reinhart
4
@ JonathonReinhart Mas, se um token expirar em breve, meu cliente terá que obter um novo token se autenticando novamente de tempos em tempos. Não é meio entediante?
smwikipedia
@ JonathonReinhart Acho que entendi por que o token tem vida curta. Por esse motivo, o servidor não precisa acompanhar a expiração de um token e, assim, abrir caminho para a escalabilidade. É meio que trade-offentre having finer control of token expiratione having better scalability.
smwikipedia
2
Isso também pode ajudar? - "Um mecanismo de segurança comum para detectar roubo de token é acompanhar as origens do endereço IP da solicitação." - descrito em detalhes na última seção aqui - firebase.google.com/docs/auth/admin/manage-sessions
Ula em
3
Teoricamente, é impossível evitar roubo de token. O melhor que podemos fazer é detectar o que aconteceu e revogar a sessão o mais rápido possível. O melhor método para detecção é usar tokens de atualização rotativos (conforme sugerido pela RFC 6819). Aqui está um blog que explica isso em detalhes: supertokens.io/blog/…
Rishabh Poddar

Respostas:

284

Eu sou o autor de uma biblioteca de nós que lida com autenticação com bastante profundidade, express-stormpath , por isso vou falar com algumas informações aqui.

Primeiro, os JWTs normalmente NÃO são criptografados. Embora exista uma maneira de criptografar JWTs (consulte: JWEs ), isso não é muito comum na prática por vários motivos.

Em seguida, qualquer forma de autenticação (usando JWTs ou não) está sujeita a ataques do MitM (man-in-the-middle). Esses ataques acontecem quando um invasor pode VER o tráfego da SUA REDE enquanto você faz solicitações pela Internet. É isso que o seu ISP pode ver, a NSA, etc.

É isso que o SSL ajuda a evitar: criptografando o tráfego de REDE do seu computador -> algum servidor ao se autenticar, um terceiro que está monitorando o tráfego da sua rede NÃO consegue ver seus tokens, senhas ou algo assim, a menos que seja capaz de alguma forma para obter uma cópia da chave SSL privada do servidor (improvável). Esta é a razão pela qual o SSL é OBRIGATÓRIO para todas as formas de autenticação.

Vamos dizer, porém, que alguém é capaz de explorar o seu SSL e é capaz de ver o seu token: a resposta à sua pergunta é que SIM , o atacante vai ser capaz de usar esse símbolo para representar você e solicitações de fazer a sua servidor.

Agora, é aqui que entram os protocolos.

JWTs são apenas um padrão para um token de autenticação. Eles podem ser usados ​​para praticamente qualquer coisa. A razão pela qual as JWTs são legais é que você pode incorporar informações extras nelas e pode validar que ninguém mexeu com elas (assinatura).

No entanto, as próprias JWTs não têm nada a ver com 'segurança'. Para todos os efeitos, os JWTs são mais ou menos a mesma coisa que as chaves de API: apenas cadeias aleatórias que você usa para se autenticar em algum servidor em algum lugar.

O que torna sua pergunta mais interessante é o protocolo que está sendo usado (provavelmente o OAuth2).

A maneira como o OAuth2 funciona é que ele foi projetado para fornecer aos clientes tokens TEMPORÁRIOS (como JWTs!) Para autenticação por apenas um PERÍODO DE CURTO TEMPO!

A idéia é que, se o seu token for roubado, o invasor poderá usá-lo apenas por um curto período de tempo.

Com o OAuth2, você precisa se autenticar novamente com o servidor de vez em quando, fornecendo suas credenciais de nome de usuário / senha OU API e, em seguida, recuperando um token em troca.

Como esse processo acontece de vez em quando, seus tokens mudam frequentemente, dificultando a personificação de invasores constantemente sem causar grandes problemas.

Espero que isso ajude ^^

rdegges
fonte
3
O autor do artigo a seguir argumenta que uma desvantagem do JWT é que a única maneira de se recuperar de um JWT roubado é gerar um novo par de chaves e efetivamente desconectar todos os usuários. Enquanto que, com os IDs de sessão armazenados em um banco de dados, o site pode excluir apenas as sessões do usuário afetado e desconectá-lo de todos os dispositivos. Não tenho certeza de como o OAuth2 se encaixa na imagem aqui ou se isso ajuda a atenuar as desvantagens apresentadas. medium.com/@rahulgolwalkar/…
Marcel
4
O autor está incorreto. Existem diferentes padrões de design que você pode usar para invalidar tokens. Mas, em geral: usar uma JWT para qualquer tipo de autenticação é uma má idéia. É muito mais eficiente usar um cookie de sessão com uma ideia de sessão incorporada que é assinada criptograficamente.
Rdegges
1
@rdegges, por favor me diga como o JWT é uma má ideia para autenticação? e como posso usar o cookie de sessão que você mencionou no seu comentário acima?
Noman tufail
6
É muito longo para digitar uma única resposta. Se você quiser saber mais, dei uma palestra detalhada sobre o assunto. Você pode conferir meus slides on-line: speakerdeck.com/rdegges/jwts-suck-and-are-stupid
rdegges
2
Teoricamente, é impossível evitar roubo de token. O melhor que podemos fazer é detectar o que aconteceu e revogar a sessão o mais rápido possível. O melhor método para detecção é usar tokens de atualização rotativos (conforme sugerido pela RFC 6819). Aqui está um blog que explica isso em detalhes: supertokens.io/blog/…
Rishabh Poddar
31

Sei que essa é uma pergunta antiga, mas acho que posso largar meus US $ 0,50 aqui, provavelmente alguém pode melhorar ou fornecer um argumento para recusar totalmente minha abordagem. Estou usando JWTs em uma API RESTful sobre HTTPS (ofc).

Para que isso funcione, você sempre deve emitir tokens de vida curta (depende da maioria dos casos, no meu aplicativo, estou definindo a expreivindicação para 30 minutos e ttl3 dias, para que você possa atualizar esse token enquanto ttlainda estiver válido e o token não estiver na lista negra )

Para que authentication service, para invalidar tokens, eu gosto de usar uma camada de cache na memória ( redis no meu caso) como JWT blacklist/ ban-listna frente, dependendo de alguns critérios: (eu sei que isso quebra a filosofia RESTful, mas os documentos armazenados são de curta duração, como eu lista negra para o tempo restante de vida - ttlreivindicação-)

Nota: os tokens na lista negra não podem ser atualizados automaticamente

  • Se user.passwordou user.emailfoi atualizado (requer confirmação de senha), o serviço de autenticação retorna um token atualizado e invalida (lista negra) os anteriores, portanto, se o seu cliente detectar que a identidade do usuário foi comprometida de alguma forma, você poderá solicitar que o usuário altere sua senha . Se você não quiser usar a lista negra para isso, poderá (mas não o encorajo a) validar a iatreivindicação (emitida em) no user.updated_atcampo (se o jwt.iat < user.updated_atJWT não for válido).
  • Usuário desconectado deliberadamente.

Finalmente, você valida o token normalmente, como todo mundo.

Nota 2: em vez de usar o próprio token (que é realmente longo) como a chave do cache, sugiro gerar e usar um token UUID para a jtireivindicação. O que é bom e acho que (não tenho certeza, já que me ocorreu) que você também pode usar esse mesmo UUID que o token CSRF, retornando um secure/ non-http-onlycookie com ele e implementando adequadamente o X-XSRF-TOKENcabeçalho usando js. Dessa forma, você evita o trabalho de computação de criar outro token para verificações de CSRF.

Frondor
fonte
9
Nunca é tarde para contribuir com sua ideia. Obrigado pela sua resposta.
smwikipedia
2
Se você armazena uma lista negra no servidor que precisa ser verificada para cada solicitação, por que não simplesmente usar uma sessão antiga simples?
Franklin Yu
@FranklinYu Uma lista negra é muito "mais barata" do que uma loja de sessão completa. Como você está armazenando objetos de valor-chave de vida curta (dependendo do tempo restante da vida útil, que deve ser bem curto), isso acontece apenas para ações de logoff e ações que invalidam os tokens; portanto, nem todos os tokens são ofc armazenado
Frondor
2
Quão barato pode ser? Antes de tudo, se você ainda estiver armazenando algo no lado do servidor, não desfrutará do benefício de "escalabilidade" reivindicado pela JWT porque ainda existe um servidor central de lista negra com o qual todo o servidor de aplicativos precisa conversar antes de fazer qualquer coisa. Se você precisar armazenar apenas uma lista negra de 1k devido à expiração rápida, poderá fazer o mesmo para as sessões e, portanto, apenas armazenar 1k de sessões.
Franklin Yu
3
Eu gosto dessa abordagem. Na verdade, você não precisa verificar a lista negra de cada solicitação, apenas em uma solicitação que ocorra após a expiração do JWT (que você pode ler a partir do próprio token) e até o período TTL seguinte. Em um caso de uso "padrão", isso deve ocorrer, no máximo, uma vez na vida útil de um determinado token. Após a atualização, você provavelmente poderá recusar quaisquer solicitações futuras de atualização. Obrigado @Frondor
John Ackerman
7

Desculpe estar um pouco atrasado com isso, mas tinha preocupações semelhantes e agora quero contribuir com algo sobre o mesmo.

1) rdegges acrescentou um ponto excelente, que o JWT não tem nada a ver com a "segurança" e simplesmente valida, se alguém mexeu com a carga útil ou não (assinatura); O ssl ajuda a evitar violações.

2) Agora, se o SSL também estiver de alguma forma comprometido, qualquer bisbilhoteiro pode roubar o nosso token de portador (JWT) e personificar o usuário genuíno, uma etapa seguinte que pode ser feita é procurar a "prova de posse" do JWT do cliente .

3) Agora, com essa abordagem, o apresentador da JWT possui uma chave de Prova de Posse (POP) específica, que o destinatário pode confirmar criptograficamente se a solicitação é do mesmo usuário autêntico ou não.

Referi-me Prova de Possesion artigo para isso e estou convencido com o apporach.

Ficarei encantado, se puder contribuir com alguma coisa.

Saúde (y)

yanky_cranky
fonte
0

Não podemos simplesmente adicionar o ip do host inicial que solicitou a geração desse token JWT como parte da reivindicação? Agora, quando o JWT é roubado e usado em uma máquina diferente, quando o servidor valida esse token, podemos verificar se o ip da máquina solicitada corresponde ao IP configurado como parte da reivindicação. Isso não corresponderia e, portanto, o token pode ser rejeitado. Além disso, se o usuário tentar manipular o token definindo seu próprio IP para o token, o token será rejeitado à medida que o token for alterado.

Venkatesh Vs
fonte
Essa é uma solução possível, mas para clientes atrás de um firewall é comum escolher um endereço IP em um pool de endereços e que pode mudar a qualquer momento.
SpeedOfSpin 21/02