Executando verificação de segurança...
17

Você realmente sabe como o JWT funciona? (Ou só acha que sabe?)

Todo mundo que trabalha com algum sistema Web com certeza usa ou pelo menos conhece esse tal desse JWT (e se não conhece, provavelmente tá fazendo merda).

Mas calma que se você não sabe, vou te explicar agora.

O JWT (JSON Web Token) é um JSON padronizado que a gente gera sem estado de token pra autenticar os serviços. Ele é famoso hoje por conseguir fazer um usuário se autenticar entre serviços que não tem acesso ao banco de usuários.

Com ele você gerencia se o usuário está logado, tempo máximo de sessão e permissionamento. E cada serviço vai validar se aquele token tem os acessos necessários pra fazer o que está tentando.

Mas, apesar de todo mundo usar, eu vejo muita gente implementando no "piloto automático", copiando e colando código sem entender o que realmente está acontecendo por baixo do capô.

E é aí que mora o perigo.

Então, pega um café, encosta na cadeira e vamos tentar entender esse negócio.

Não vou te jogar definições de dicionário; quero que você entenda a mecânica da coisa, como se estivéssemos discutindo a arquitetura do seu próximo projeto.

O Problema: Quem é você e o que você faz aqui?

Para entender o porquê do JWT existir, precisamos voltar um passo. O problema fundamental da web é que o protocolo HTTP é stateless (sem estado).

Isso significa que o servidor tem memória curta. Você faz um login agora, mas na próxima requisição, o servidor já esqueceu quem você é.

Antigamente, resolvíamos isso com Sessões (Stateful).

Funcionava assim: você logava, o servidor criava um arquivo na memória dele (uma sessão) e te dava um ID (o session_id), que geralmente ficava num cookie. Toda vez que você voltava, mostrava esse ID, o servidor ia lá na memória, buscava os dados e confirmava: "Ah, é o fulano".

Isso é ótimo... até você ter milhões de usuários ou precisar escalar horizontalmente.

Imagina ter 50 servidores. Se a sessão foi criada no Servidor 1 e a próxima requisição cair no Servidor 2, o Servidor 2 não vai te conhecer. Aí você precisa de bancos de dados para compartilhar sessão (tipo Redis), e a infraestrutura começa a ficar cara e complexa.

A solução: Chave stateless com JWT

Como não dá pra ficar contando com a web manter o estado da aplicação desse jeito, então porque não abração o stateless?

E é bem genial se você pensar: “e se ao invés de salvarmos o dado, pedirmos pro usuário guardar pra gente?”.

O JWT faz exatamente isso. Ele é como um doc assinado digitalmente pelo seu autenticador pra dizer quem você é e o que você pode ou não fazer.

Pense nele como um Passaporte. Quando você chega na imigração de um país, o oficial não liga para o governo do seu país de origem para perguntar se você é você. Ele olha o passaporte. Ele confia no documento porque:

  1. Tem um padrão específico.
  2. Tem uma foto e dados legíveis.
  3. O mais importante: tem selos de segurança e marcas d'água (assinatura) que provam que aquele documento não foi forjado.

Com o JWT, o servidor gera esse "passaporte", te entrega e diz: "Cuida disso. Quando quiser algo, me mostra." O servidor não guarda nada. Zero memória ocupada.

Anatomia do JWT

Se você já viu um JWT sabe que é basicamente uma string gigante separada por pontos.

No fim, não é nada complicado e é fácil de ler se você pensar bem.

Ele é dividido em três partes:

{HEADER}.{PAYLOAD}.{SIGNATURE}

1 - O header

A primeira parte é apenas um JSON codificado em Base64Url (lembre-se disso: codificado, não criptografado!). Ele geralmente diz duas coisas simples:

  • alg: Qual algoritmo foi usado para assinar (ex: HS256 ou RS256).
  • typ: O tipo do token (JWT).

Ele é assim:

{
  "alg": "HS256", // Algoritmo de Hash (HMAC SHA-256)
  "typ": "JWT"
}

2 - O Payload

Aqui é onde vivem os dados, que chamamos tecnicamente de Claims (afirmações).

É aqui que ficam as informações de verdade.

Aqui você vai ter coisas como:

  • sub (Subject): O ID do usuário.
  • name: O nome do usuário.
  • iat (Issued At): Quando foi criado.
  • exp (Expiration): Quando esse token morre (essencial!).

Cuidado de amigo aqui:

Como eu disse, isso é apenas Base64. Qualquer pessoa que pegar seu token pode jogar num site tipo jwt.io e ler o que está escrito aqui. Nunca, jamais, em hipótese alguma coloque senhas ou dados sensíveis no Payload. O JWT garante autenticidade (que o dado não foi alterado), mas não garante confidencialidade (que o dado não será lido).

Algo assim:

{
  "sub": "1234567890",  // ID do Usuário
  "name": "João da Silva",
  "role": "admin",      // Autorização
  "iat": 1516239022     // Criado em (Timestamp)
}

3 - A Signature

É aqui que tá a segurança dele.

Essa parte é a que impede que eu pegue seu token e altere minhas permissões pra controlar seu sistema.

O servidor pega o header e o payload e cria um hash usando uma chave secreta que só ele tem e gera essa signature.

A fórmula é mais ou menos assim:

Assinatura = HMACSHA256(base64(Header) + "." + base64(Payload), SEGREDO_DO_SERVIDOR)

Quando o token volta para o servidor, ele refaz essa conta. Se a assinatura bater com a que veio no token, ele aceita. Se você mudou uma vírgula no Payload, a matemática muda completamente, a assinatura não bate e o servidor te bloqueia na hora.

Nível Avançado: Como assinar isso?

Aqui entra uma decisão de arquitetura importante. Existem dois jeitos principais de assinar tokens:

  1. Symmetric (HS256):

É como um aperto de mão secreto. O servidor que cria o token e o servidor que lê o token usam a mesma senha para gerar e validar a assinatura. É rápido e eficiente, mas todos os seus microsserviços precisam saber a senha secreta. Se um vazar, já era.

  1. Asymmetric (RS256):

Aqui usamos um par de chaves (Privada e Pública). O servidor de Autenticação usa a Chave Privada para criar e assinar o token. Todos os outros serviços usam a Chave Pública apenas para verificar se a assinatura é válida.

Por que isso é incrível? Porque o serviço que valida o token não consegue criar tokens falsos (ele não tem a chave privada). É muito mais seguro para arquiteturas grandes.

O "Calcanhar de Aquiles" do JWT

É claro que o JWT não é perfeito.

Ele tem um problema estrutural que você precisa resolver no seu design: Revogação.

Lembra que o servidor não guarda estado? Se eu te dou um passaporte válido por 7 dias, e no segundo dia eu descubro que você é um espião, eu não tenho como "desligar" seu passaporte remotamente, porque o passaporte está com você, não comigo.

Se um hacker rouba um JWT válido, ele tem acesso total até aquele token expirar. O servidor não tem uma lista de "tokens ativos" para consultar (se tivesse, voltávamos ao problema de sessão no banco de dados).

Como lidamos com isso?

  1. Tokens de vida curta: Fazemos o access_token durar pouco (ex: 15 minutos).
  2. Refresh Tokens: Usamos um segundo token, de longa duração, apenas para pedir novos tokens de acesso. Nesse momento de "renovação", o servidor pode checar no banco se o usuário ainda está ativo ou se foi banido.

Onde guardar essa coisa?

Essa é a pergunta de um milhão de dólares. No Frontend, onde guardamos o JWT?

LocalStorage?

É fácil, mas é perigoso. Qualquer script malicioso (XSS) rodando na sua página pode ler seu LocalStorage e roubar o token.

Cookie HttpOnly?

É mais seguro contra roubo via script, mas te deixa vulnerável a ataques CSRF (quando um site malicioso usa seu cookie para fazer requisições sem você saber), embora hoje em dia os navegadores com a flag SameSite mitiguem bem isso.

Para aplicações de alta segurança, a combinação de Cookies HttpOnly com flags de segurança (Secure, SameSite) costuma ser a aposta mais segura.

Resumo da Ópera

O JWT é poderoso porque permite escalar. Ele tira a carga das costas do servidor e permite que sistemas distribuídos conversem de forma segura. Mas ele exige responsabilidade.

Entender que o JWT é um contrato de confiança assinado, e não um cofre criptografado, é o primeiro passo para não cometer erros básicos de segurança. Use-o para transmitir identidade (quem é o usuário) e autorização (o que ele pode fazer), mantenha o tempo de expiração curto e escolha bem o algoritmo de assinatura.

No fim das contas, é tudo sobre trocar estado por criptografia. E agora que você sabe como a mágica funciona, fica muito mais fácil debugar aquele erro 401 na sexta-feira à tarde.

Carregando publicação patrocinada...
3

Só uma curiosidade rápida sobre JWT antigamente havia uma vulnerabilidade famosa do alg: "none". Antigamente, algumas libs aceitavam tokens sem assinatura se alguém trocasse o algoritmo pra "none" ou enganavam o backend trocando RS256 por HS256. Hoje as libs modernas geralmente bloqueiam isso, e é recomendado que você configure explicitamente quais algoritmos vc quer aceitar.

Ou seja: se o dev não define o algorithms: ["RS256"] (ou o que for), a biblioteca tenta adivinhar… e adivinha quem ama quando a biblioteca tenta adivinha: o atacante.

e sobre o alg: "none" essa vulnerabilidade ainda deve está ativas em sistemas legados que nunca fizeram upgrade das libs.

2

O "Calcanhar de Aquiles" do JWT
Ele tem um problema estrutural que você precisa resolver no seu design: Revogação.

Esse é um problema da tecnologia ou é a tecnologia sendo usada de uma forma que ela não foi proposta?

JWT é feito para autenticação, não autorização

JWT serve únicamente com o propósito de dizer "A pessoa que está acessando o seu sistema é a pessoa real"

Se você precisa revogar é porque a pessoa não tem mais a autorização de acessar esse recurso. A pessoa continua sendo ela, só não tem mais os poderes que ela tinha.

E o JWT nunca foi feito para autorizar um acesso

Conteúdo excluído
4

Não entendi muito bem o q vc quis dizer. Mas pelo q entendi vc concluiu q o JWT não é necessário por conta do HTTPS criptografar a conexão entre cliente e servidor.

Mas as coisas não são tão simples. O https protege os dados de serem interceptados no caminho atéo servidor, porém o frontend é inteiramente executado pelo cliente. isso significa q tudo q o seu site comunica ao servidor pode ser emulado fora do navegador com curl ou wget por exemplo, ou por meio de scripts. em outras palavras, uma pessoa mal intencionada pode, e provavelmente vai, tentar mandar requests irregulares para tentar roubar informações ou causar algum prejuízo.

O JWT serve para autenticar o usuário, e não para proteger informações. Ele é uma forma de assinatura para garantir a identidade do usuário.

3

que doideira, isso passou longe, me pergunto se tem algum ódio pessoal contra o JWT que nem se deu ao trabalho de ler e ja foi comentado qualquer coisa sem nenhum tipo de embasamento lógico.

É tipo vc me perguntar o que é melhor um carrinho de mão ou uma Ferrari, dependendo do que você quer fazer. vc que carregar cimento para o segundo andar de uma contrução? ou andar de forma extravagante pela cidade?

São duas coisas diferentes que fazem seu trabalho perfeitamente mas um não faz o trabalho do outro.