Tokens JWT! o que são? o que comem? onde vivem?

Pedro Matias de Araujo
devorando
Published in
6 min readFeb 4, 2020

--

Aviso aos navegantes: esse papo aqui é dev para dev, morô? então se quiser continuar lendo, é por sua conta em risco, saiba que vai ter muito termo técnico aqui, e se não souber algum, pare o texto, pesquise o que significa e volte para aqui

Olá pessoal, eu sou o Pedro (ou Matias), desenvolvedor full stack aqui no aiqfome. Hoje vou falar agora sobre algo que todo o dev já deve ter mexido na vida, o fucking token. (eu não obriguei você a ler aquele textão sobre hash à toa), especificamente os tokens JWT.

O que é token?

A palavra significa “passe” e remete à um código aleatório, gerado no servidor e passado para o cliente, que tem que ser enviado a cada requisição para o servidor saber que o cliente é ele mesmo. Desta forma, ninguém poderá adivinhar o código, já que ele é gerado aleatoriamente.

Ah! Outra coisa importante, o token é válido por um tempo fixo, tendo que ser gerado outro após esse período, o que dificulta ainda mais a ação de alguém querendo adivinhar o seu token e tentar ser você.

Tá, já entendi o T e o JW?

JWT significa JSON Web Token e é um padrão (RFC-7519) de mercado que define como transmitir e armazenar objetos JSON de forma compacta e segura entre diferentes aplicações. Os dados contidos nele podem ser validados a qualquer momento pois o token é assinado digitalmente.

Tem todas as propriedades de um token normal, com adição de que consegue guardar informação dentro dele, sem precisar ir ao banco para buscar algumas informações como usuário do token, quando ele expira, etc. (parabéns para quem teve essa ideia)

O conceito é parecido com uma carteira de motorista: você vai no DETRAN, mostra uma documentação válida e eles geram uma carteira de motorista para você. Quando for parado pelo Polícia e solicitarem o seu documento, eles não precisam ir perguntar para o DETRAN, coisas como: qual é o tipo da carteira, se a carteira ainda está valida ou em qual estado você tirou ela, está tudo contido na própria carteira, assim como um token JWT.

Um token JWT é composto por três componentes básicos: HEADER, PAYLOAD e SIGNATURE. Vou explicar o que é cada um

HEADER

O Header é um objeto JSON que define informações sobre o tipo do token (typ), nesse caso JWT, e o algoritmo de criptografia usado em sua assinatura (alg), normalmente HMAC SHA256(que usa a mesma chave para criptografar e descriptografar) ou RSA (usa o conceito de chave pública/privada - ainda não falei, mas tem um texto em inglês falando sobre aqui).

{
"alg" : "HS256",
"typ" : "JWT"
}

PAYLOAD

O Payload é um objeto JSON com as Claims (informações) da entidade tratada. Normalmente o usuário autenticado.

Essas claims podem ser de 3 tipos:

  • Reserved claims: atributos não obrigatórios (mas recomendados) que são usados na validação do token pelos protocolos de segurança das APIs.

sub (subject) = Entidade a quem o token pertence, normalmente o ID do usuário;
iss (issuer) = Emissor do token;
exp (expiration) = Timestamp de quando o token irá expirar;
iat (issued at) = Timestamp de quando o token foi criado;
aud (audience) = Destinatário do token, representa a aplicação que irá usá-lo.

Geralmente os atributos mais utilizados são: sub, iss e exp.

  • Public claims: atributos que usamos em nossas aplicações. Normalmente é armazenado as informações do usuário autenticado na aplicação.

name
roles
permissions

  • Private claims: atributos definidos especialmente para compartilhar informações entre aplicações.

Parece óbvio mas às vezes não é: Por segurança, recomenda-se NÃO ARMAZENAR INFORMAÇÕES CONFIDENCIAIS OU SENSÍVEIS NO TOKEN.

BASE64

Antes de falar sobre a assinatura do token, base64 NÃO É CRIPTOGRAFIA, então transformar sua string em base64 não deixará ela segura. É um método para codificação de dados para transferência na Internet. E codificar é diferente de criptografar, embora pareçam falar da mesma coisa (talvez fale sobre isso em algum post no futuro), até eu erro o termo correto às vezes.

Então quando falar de base64, é só uma forma de transformar sua string em uma forma de ser mais fácil de ser enviada. Segura esse pensamento.

SIGNATURE

A assinatura de um JSON Web Token é seu componente mais sensível por tratar justamente da segurança deste token. Por conta disto existe uma fórmula padrão para que o token seja adequadamente assinado, exigindo que o token seja uma hash em Base64 (ohhh) gerada de um algoritmo de criptografia, por exemplo SHA256 ou SHA512, e essa hash precisa ser feita a partir do header e do payload do token.

Essa assinatura é utilizada para garantir a integridade do token, ou seja, se ele foi modificado e se realmente foi gerado por você.

HMAC-SHA256(
base64urlEncoding(header) + '.' +
base64urlEncoding(payload),
secret
)

Isso previne ataques do tipo man-in-the-middle, nos quais o invasor poderia interceptar a requisição e modificar seu conteúdo, por exemplo, alterar o usuário do token. Caso o payload seja alterado, a hash final não será válida pois não foi assinada com sua chave secreta.

Apenas quem está de posse da chave pode criar, alterar e validar o token.

Resultado final

O resultado final é um token com três seções (header, payload, signature) separadas por “.” — ponto.

Detalhe: embora o token seja assinado digitalmente o seu header e payload ainda conseguem ser vistos, pois somente são codificados em base64 (pode testar se não acreditar em mim, basta decodificar em base64 o header e o payload do token abaixo).

Por exemplo: criei esse token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyNTk1NjgiLCJmb21pbmhhIjoiUGVkcm8gTWF0aWFzIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzk5MjIsImZhdm9yaXRlX2Zvb2QiOiJEb2fDo28iLCJudW1iZXJfb2Zfb3JkZXJzIjoxMjE0fQ.z_ot0OhPmtIrt6r_eTGSrKIynhxQ_eo6dvtcgsv86Zk

Todas as informações de header e payload pode ser vistas, por exemplo, no site jwt.io, sem precisar do secret key, por isso, repito: não coloque informações sensíveis no token JWT.

Com um token construído e seguro, é computacionalmente inviável decodificar a assinatura sem ter a secret key da aplicação (tem uma matemática pesada por baixo, mas usa alguns conceitos de hash que já falei aqui). Porém, uma vez em posse da secret key, qualquer aplicação pode decodificar a assinatura e verificar se ela é válida.

Então a lógica para validar o token é basicamente usar o header e o payload, criptografando com a secret key. Uma vez que a signature é a mesma, então esse cliente está autenticado na aplicação. (a senha do token que passei é aiqfome, então podem validar a signature dele).

Tá, estou com o token, como eu uso isso?

Ao fazer login em um serviço de autenticação um token JWT é criado e retornado para o cliente. Esse token deve ser enviado, por exemplo, para as APIs através do header Authorization de cada requisição HTTP com a flag Bearer.

Authorization: Bearer <token>

Em posse do token, a API não precisa ir até o banco de dados consultar as informações do usuário, pois essas informações estão contidas no próprio token (repito, melhor coisa que já fizeram!!).

E no aiqfome?

Aqui estamos quebrando nossa arquitetura e reconstruindo como microsserviços, isso ajuda muito mais na escalabilidade do projeto, já que temos 2 grandes picos de uso durante o dia.

Dessa forma a autenticação e autorização dos serviços são feitas através desse tipo de token. Assim conseguimos ganhar performance, já que não são necessárias consultas desnecessárias para trazer dados ou para verificar se o token está válido, já que tokens JWT são autocontidos, e a informação se está expirado também está com o próprio token.

Aqui usamos algumas bibliotecas que ajudam a mexer com esses tokens, como por exemplo:

  • jsonwebtoken — para nossos módulos em Node.js;
  • pyJWT — para os módulos em Python;

Ah vai ter uma parte dois desse assunto, senão iria ficar muito grande, aguardem 😉

SUGESTÕES, RECLAMAÇÕES, DÚVIDAS E ELOGIOS

Por favor falar com o Clodoaldo. Ele tá sempre no twitter, instagram, face, e até no linkedin do aiq.

Mentira, o Crô é mó ocupado, pode me responder por aqui mesmo ou conversar comigo no Linkedin!

Isso é tudo pessoal, até a próxima 😉

--

--